Skip to content

Commit 87dffde

Browse files
committed
Adding customizable auto-indent text function
1 parent c1c0e57 commit 87dffde

4 files changed

Lines changed: 201 additions & 0 deletions

File tree

data/io.github.phase1geo.textshine.appdata.xml.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
<li>Fixed issue where a non-text file is attempted to be inserted into the text area.</li>
104104
<li>Fixed case actions to allow non-English words to be modified correctly.</li>
105105
<li>Fixed issue with using regular expressions from dropdown menus.</li>
106+
<li>Fixed issues with some of the action copy functions.</li>
106107
</ul>
107108
</description>
108109
</release>

src/TextFunctions.vala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ public class TextFunctions {
124124
add_function( "indent", new Indent() );
125125
add_function( "indent", new Unindent() );
126126
add_function( "indent", new IndentXML() );
127+
add_function( "indent", new IndentDelim() );
127128

128129
// Category - convert
129130
add_function( "convert", new ConvertHardWrap() );
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Copyright (c) 2020-2026 (https://github.com/phase1geo/TextShine)
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2 of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public
15+
* License along with this program; if not, write to the
16+
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17+
* Boston, MA 02110-1301 USA
18+
*
19+
* Authored by: Trevor Williams <phase1geo@gmail.com>
20+
*/
21+
22+
using Gtk;
23+
using Xml;
24+
25+
public class IndentDelim : TextFunction {
26+
27+
private string[] _start_delims = { "{", "[" };
28+
private string[] _end_delims = { "}", "]" };
29+
private string[] _ignore_delims = { "\"", "'" };
30+
31+
//-------------------------------------------------------------
32+
// Constructor
33+
public IndentDelim( bool custom = false ) {
34+
base( "indent-delim", custom );
35+
}
36+
37+
protected override string get_label0() {
38+
return( _( "Indent With Custom Delimiters" ) );
39+
}
40+
41+
public override TextFunction copy( bool custom ) {
42+
var copy = new IndentDelim( custom );
43+
copy._start_delims = _start_delims;
44+
copy._end_delims = _end_delims;
45+
copy._ignore_delims = _ignore_delims;
46+
return( copy );
47+
}
48+
49+
public override bool settings_available() {
50+
return( true );
51+
}
52+
53+
//-------------------------------------------------------------
54+
// Populates the given popover with the settings
55+
public override void add_settings( Grid grid ) {
56+
add_string_setting( grid, 0, _( "Indent delimiters" ), string.joinv( ",", _start_delims ), (value) => {
57+
_start_delims = value.split( "," );
58+
});
59+
add_string_setting( grid, 1, _( "Unindent delimiters" ), string.joinv( ",", _end_delims ), (value) => {
60+
_end_delims = value.split( "," );
61+
});
62+
add_string_setting( grid, 2, _( "Ignore delimiters" ), string.joinv( ",", _ignore_delims ), (value) => {
63+
_ignore_delims = value.split( "," );
64+
});
65+
}
66+
67+
public override Xml.Node* save() {
68+
Xml.Node* node = base.save();
69+
node->set_prop( "indent", string.joinv( ",", _start_delims ) );
70+
node->set_prop( "unindent", string.joinv( ",", _end_delims ) );
71+
node->set_prop( "ignore", string.joinv( ",", _ignore_delims ) );
72+
return( node );
73+
}
74+
75+
public override void load( Xml.Node* node, TextFunctions functions ) {
76+
base.load( node, functions );
77+
var i = node->get_prop( "indent" );
78+
if( i != null ) {
79+
_start_delims = i.split( "," );
80+
}
81+
var u = node->get_prop( "unindent" );
82+
if( u != null ) {
83+
_end_delims = u.split( "," );
84+
}
85+
var ignore = node->get_prop( "ignore" );
86+
if( ignore != null ) {
87+
_ignore_delims = ignore.split( "," );
88+
}
89+
}
90+
91+
//-------------------------------------------------------------
92+
// Returns true if the given text string contains an ignore
93+
// delimiter.
94+
private bool ends_with_delims( string text, ref string[] delims, out string matched ) {
95+
matched = "";
96+
foreach( var delim in delims ) {
97+
if( text.has_suffix( delim ) ) {
98+
matched = delim;
99+
return( true );
100+
}
101+
}
102+
return( false );
103+
}
104+
105+
//-------------------------------------------------------------
106+
// Perform the transformation
107+
public override string transform_text( string original, int cursor_pos ) {
108+
109+
var new_text = new StringBuilder();
110+
var indent = 0;
111+
var escaped = false;
112+
var ignored = false;
113+
var ignore_delim = "";
114+
var nl_added = false;
115+
116+
foreach( var line in original.split( "\n" ) ) {
117+
118+
var curr_line = "";
119+
var trimmed = line.strip();
120+
121+
if( indent > 0 ) {
122+
new_text.append( string.nfill( indent, '\t' ) );
123+
}
124+
125+
for( int i=0; i<trimmed.length; i++ ) {
126+
127+
if( !trimmed.valid_char( i ) ) {
128+
continue;
129+
}
130+
131+
var ch = trimmed.get_char( i );
132+
133+
stdout.printf( "curr_line: %s (%s)\n", curr_line, ch.to_string() );
134+
135+
if( nl_added ) {
136+
nl_added = false;
137+
}
138+
139+
if( escaped ) {
140+
escaped = false;
141+
curr_line += ch.to_string();
142+
continue;
143+
}
144+
145+
if( ch == '\\' ) {
146+
escaped = true;
147+
curr_line += ch.to_string();
148+
continue;
149+
}
150+
151+
var str = curr_line + ch.to_string();
152+
var matched = "";
153+
154+
if( ends_with_delims( str, ref _ignore_delims, out matched ) && (!ignored || (ignore_delim == matched)) ) {
155+
ignored = !ignored;
156+
ignore_delim = matched;
157+
curr_line += ch.to_string();
158+
continue;
159+
}
160+
161+
if( ignored ) {
162+
curr_line += ch.to_string();
163+
continue;
164+
}
165+
166+
if( ends_with_delims( str, ref _start_delims, out matched ) ) {
167+
indent++;
168+
new_text.append( str.slice( 0, (str.length - matched.length) ) + matched + "\n" + string.nfill( indent, '\t' ) );
169+
curr_line = "";
170+
nl_added = true;
171+
continue;
172+
}
173+
174+
if( ends_with_delims( str, ref _end_delims, out matched ) ) {
175+
indent--;
176+
new_text.append( str.slice( 0, (str.length - matched.length) ) + "\n" + string.nfill( indent, '\t' ) + matched );
177+
curr_line = "";
178+
nl_added = true;
179+
continue;
180+
}
181+
182+
curr_line = str;
183+
184+
}
185+
186+
if( nl_added ) {
187+
nl_added = false;
188+
} else {
189+
new_text.append( curr_line + "\n" );
190+
}
191+
192+
}
193+
194+
return( new_text.str );
195+
196+
}
197+
198+
}

src/functions/indent/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
sources += files(
22

33
'Indent.vala',
4+
'IndentDelim.vala',
45
'IndentXML.vala',
56
'Unindent.vala'
67

0 commit comments

Comments
 (0)