|
| 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 | +} |
0 commit comments