diakonos 0.8.11 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +439 -0
- data/LICENCE.md +675 -0
- data/bin/diakonos +6 -0
- data/diakonos-256-colour.conf +220 -0
- data/diakonos.conf +1802 -0
- data/help/about-help.dhf +31 -0
- data/help/clipboard.dhf +45 -0
- data/help/close-file.dhf +6 -0
- data/help/code-block-navigation.dhf +16 -0
- data/help/column-markers.dhf +15 -0
- data/help/config.dhf +69 -0
- data/help/cursor-stack.dhf +19 -0
- data/help/delete.dhf +41 -0
- data/help/extensions.dhf +125 -0
- data/help/file-type.dhf +24 -0
- data/help/key-mapping.dhf +127 -0
- data/help/line-numbers.dhf +22 -0
- data/help/macros.dhf +27 -0
- data/help/new-file.dhf +6 -0
- data/help/open-file.dhf +21 -0
- data/help/quit.dhf +7 -0
- data/help/resizing.dhf +19 -0
- data/help/ruby.dhf +17 -0
- data/help/save-file.dhf +10 -0
- data/help/scripting.dhf +92 -0
- data/help/search.dhf +103 -0
- data/help/shell.dhf +60 -0
- data/help/speed.dhf +23 -0
- data/help/support.dhf +15 -0
- data/help/switch-buffers.dhf +15 -0
- data/help/tabs.dhf +36 -0
- data/help/undo.dhf +9 -0
- data/help/uninstall.dhf +18 -0
- data/help/welcome.dhf +32 -0
- data/help/word-wrap.dhf +17 -0
- data/lib/diakonos/about.rb +70 -0
- data/lib/diakonos/bookmark.rb +46 -0
- data/lib/diakonos/buffer/bookmarking.rb +47 -0
- data/lib/diakonos/buffer/cursor.rb +335 -0
- data/lib/diakonos/buffer/delete.rb +170 -0
- data/lib/diakonos/buffer/display.rb +362 -0
- data/lib/diakonos/buffer/file.rb +157 -0
- data/lib/diakonos/buffer/indentation.rb +175 -0
- data/lib/diakonos/buffer/searching.rb +552 -0
- data/lib/diakonos/buffer/selection.rb +360 -0
- data/lib/diakonos/buffer/undo.rb +73 -0
- data/lib/diakonos/buffer-hash.rb +60 -0
- data/lib/diakonos/buffer-management.rb +59 -0
- data/lib/diakonos/buffer.rb +698 -0
- data/lib/diakonos/clipboard-klipper-dbus.rb +62 -0
- data/lib/diakonos/clipboard-klipper.rb +62 -0
- data/lib/diakonos/clipboard-osx.rb +59 -0
- data/lib/diakonos/clipboard-xclip.rb +60 -0
- data/lib/diakonos/clipboard.rb +47 -0
- data/lib/diakonos/config-file.rb +67 -0
- data/lib/diakonos/config.rb +382 -0
- data/lib/diakonos/core-ext/enumerable.rb +15 -0
- data/lib/diakonos/core-ext/hash.rb +60 -0
- data/lib/diakonos/core-ext/object.rb +6 -0
- data/lib/diakonos/core-ext/regexp.rb +6 -0
- data/lib/diakonos/core-ext/string.rb +122 -0
- data/lib/diakonos/ctag.rb +28 -0
- data/lib/diakonos/cursor.rb +27 -0
- data/lib/diakonos/display/format.rb +75 -0
- data/lib/diakonos/display.rb +336 -0
- data/lib/diakonos/extension-set.rb +49 -0
- data/lib/diakonos/extension.rb +34 -0
- data/lib/diakonos/finding.rb +40 -0
- data/lib/diakonos/functions/basics.rb +34 -0
- data/lib/diakonos/functions/bookmarking.rb +61 -0
- data/lib/diakonos/functions/buffers.rb +491 -0
- data/lib/diakonos/functions/clipboard.rb +70 -0
- data/lib/diakonos/functions/cursor.rb +264 -0
- data/lib/diakonos/functions/grepping.rb +83 -0
- data/lib/diakonos/functions/indentation.rb +71 -0
- data/lib/diakonos/functions/readline.rb +93 -0
- data/lib/diakonos/functions/search.rb +179 -0
- data/lib/diakonos/functions/selection.rb +98 -0
- data/lib/diakonos/functions/sessions.rb +78 -0
- data/lib/diakonos/functions/shell.rb +250 -0
- data/lib/diakonos/functions/tags.rb +65 -0
- data/lib/diakonos/functions/text-manipulation.rb +196 -0
- data/lib/diakonos/functions-deprecated.rb +77 -0
- data/lib/diakonos/functions.rb +292 -0
- data/lib/diakonos/grep.rb +98 -0
- data/lib/diakonos/help.rb +47 -0
- data/lib/diakonos/hooks.rb +13 -0
- data/lib/diakonos/installation.rb +19 -0
- data/lib/diakonos/interaction-handler.rb +216 -0
- data/lib/diakonos/interaction.rb +52 -0
- data/lib/diakonos/key-map.rb +62 -0
- data/lib/diakonos/keying.rb +442 -0
- data/lib/diakonos/line-mover.rb +42 -0
- data/lib/diakonos/list.rb +59 -0
- data/lib/diakonos/logging.rb +27 -0
- data/lib/diakonos/mode.rb +17 -0
- data/lib/diakonos/mouse.rb +18 -0
- data/lib/diakonos/number-fitter.rb +11 -0
- data/lib/diakonos/range.rb +31 -0
- data/lib/diakonos/readline/functions.rb +82 -0
- data/lib/diakonos/readline.rb +223 -0
- data/lib/diakonos/search.rb +58 -0
- data/lib/diakonos/sessions.rb +257 -0
- data/lib/diakonos/sized-array.rb +48 -0
- data/lib/diakonos/text-mark.rb +19 -0
- data/lib/diakonos/vendor/fuzzy_file_finder.rb +386 -0
- data/lib/diakonos/version.rb +25 -0
- data/lib/diakonos/window.rb +43 -0
- data/lib/diakonos.rb +592 -0
- metadata +160 -68
@@ -0,0 +1,698 @@
|
|
1
|
+
module Diakonos
|
2
|
+
|
3
|
+
class Buffer
|
4
|
+
attr_reader :name, :original_language, :language, :changing_selection, :read_only,
|
5
|
+
:tab_size, :selection_mode
|
6
|
+
attr_writer :desired_column, :read_only
|
7
|
+
attr_accessor :lines
|
8
|
+
|
9
|
+
TYPING = true
|
10
|
+
STOPPED_TYPING = true
|
11
|
+
STILL_TYPING = false
|
12
|
+
NO_SNAPSHOT = true
|
13
|
+
DO_DISPLAY = true
|
14
|
+
DONT_DISPLAY = false
|
15
|
+
READ_ONLY = true
|
16
|
+
READ_WRITE = false
|
17
|
+
ROUND_DOWN = false
|
18
|
+
ROUND_UP = true
|
19
|
+
PAD_END = true
|
20
|
+
DONT_PAD_END = false
|
21
|
+
MATCH_CLOSE = true
|
22
|
+
MATCH_ANY = false
|
23
|
+
START_FROM_BEGINNING = -1
|
24
|
+
DO_PITCH_CURSOR = true
|
25
|
+
DONT_PITCH_CURSOR = false
|
26
|
+
STRIP_LINE = true
|
27
|
+
DONT_STRIP_LINE = false
|
28
|
+
USE_INDENT_IGNORE = true
|
29
|
+
DONT_USE_INDENT_IGNORE = false
|
30
|
+
WORD_REGEXP = /\w+/
|
31
|
+
|
32
|
+
# Set name to nil to create a buffer that is not associated with a file.
|
33
|
+
# @param [Hash] options
|
34
|
+
# @option options [String] 'filepath'
|
35
|
+
# A file path (which is expanded internally)
|
36
|
+
# @option options [Boolean] 'read_only' (READ_WRITE)
|
37
|
+
# Whether the buffer should be protected from modification
|
38
|
+
# @option options [Hash] 'cursor'
|
39
|
+
# A Hash containing 'row' and/or 'col' indicating where the cursor should
|
40
|
+
# initially be placed. Defaults: 0 and 0
|
41
|
+
# @option options [Hash] 'display'
|
42
|
+
# A Hash containing 'top_line' and 'left_column' indicating where the view
|
43
|
+
# should be positioned in the file. Defaults: 0 and 0
|
44
|
+
# @see READ_WRITE
|
45
|
+
# @see READ_ONLY
|
46
|
+
def initialize( options = {} )
|
47
|
+
@name = options[ 'filepath' ]
|
48
|
+
@modified = false
|
49
|
+
@last_modification_check = Time.now
|
50
|
+
|
51
|
+
@buffer_states = Array.new
|
52
|
+
@cursor_states = Array.new
|
53
|
+
if @name.nil?
|
54
|
+
@lines = Array.new
|
55
|
+
@lines[ 0 ] = ""
|
56
|
+
else
|
57
|
+
@name = File.expand_path( @name )
|
58
|
+
if FileTest.exist? @name
|
59
|
+
@lines = IO.readlines( @name )
|
60
|
+
if ( @lines.length == 0 ) || ( @lines[ -1 ][ -1..-1 ] == "\n" )
|
61
|
+
@lines.push ""
|
62
|
+
end
|
63
|
+
@lines = @lines.collect do |line|
|
64
|
+
line.chomp
|
65
|
+
end
|
66
|
+
else
|
67
|
+
@lines = Array.new
|
68
|
+
@lines[ 0 ] = ""
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
@current_buffer_state = 0
|
73
|
+
|
74
|
+
options[ 'display' ] ||= Hash.new
|
75
|
+
@top_line = options[ 'display' ][ 'top_line' ] || 0
|
76
|
+
@left_column = options[ 'display' ][ 'left_column' ] || 0
|
77
|
+
@desired_column = @left_column
|
78
|
+
@mark_anchor = nil
|
79
|
+
@text_marks = Hash.new
|
80
|
+
@selection_mode = :normal
|
81
|
+
@last_search_regexps = Array( options['last_search_regexps'] ).map { |r| Regexp.new(r) }
|
82
|
+
@highlight_regexp = nil
|
83
|
+
@last_search = nil
|
84
|
+
@changing_selection = false
|
85
|
+
@typing = false
|
86
|
+
options[ 'cursor' ] ||= Hash.new
|
87
|
+
@last_col = options[ 'cursor' ][ 'col' ] || 0
|
88
|
+
@last_row = options[ 'cursor' ][ 'row' ] || 0
|
89
|
+
@last_screen_y = @last_row - @top_line
|
90
|
+
@last_screen_x = @last_col - @left_column
|
91
|
+
@last_screen_col = @last_screen_x
|
92
|
+
@read_only = options[ 'read_only' ] || READ_WRITE
|
93
|
+
@bookmarks = Array.new
|
94
|
+
@lang_stack = Array.new
|
95
|
+
|
96
|
+
configure
|
97
|
+
|
98
|
+
if @settings[ "convert_tabs" ]
|
99
|
+
tabs_subbed = false
|
100
|
+
@lines.collect! do |line|
|
101
|
+
new_line = line.expand_tabs( @tab_size )
|
102
|
+
tabs_subbed = ( tabs_subbed || new_line != line )
|
103
|
+
# Return value for collect:
|
104
|
+
new_line
|
105
|
+
end
|
106
|
+
@modified = ( @modified || tabs_subbed )
|
107
|
+
if tabs_subbed
|
108
|
+
$diakonos.set_iline "(spaces substituted for tab characters)"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
@buffer_states[ @current_buffer_state ] = @lines
|
113
|
+
@cursor_states[ @current_buffer_state ] = [ @last_row, @last_col ]
|
114
|
+
end
|
115
|
+
|
116
|
+
def configure(
|
117
|
+
language = (
|
118
|
+
$diakonos.get_language_from_shabang( @lines[ 0 ] ) ||
|
119
|
+
$diakonos.get_language_from_name( @name ) ||
|
120
|
+
LANG_TEXT
|
121
|
+
)
|
122
|
+
)
|
123
|
+
reset_display
|
124
|
+
set_language language
|
125
|
+
@original_language = @language
|
126
|
+
end
|
127
|
+
|
128
|
+
def reset_display
|
129
|
+
@win_main = $diakonos.win_main
|
130
|
+
@win_line_numbers = $diakonos.win_line_numbers
|
131
|
+
end
|
132
|
+
|
133
|
+
def set_language( language )
|
134
|
+
@settings = $diakonos.settings
|
135
|
+
@language = language
|
136
|
+
@surround_pairs = $diakonos.surround_pairs[ @language ]
|
137
|
+
@token_regexps = $diakonos.token_regexps[ @language ]
|
138
|
+
@close_token_regexps = $diakonos.close_token_regexps[ @language ]
|
139
|
+
@token_formats = $diakonos.token_formats[ @language ]
|
140
|
+
@indenters = $diakonos.indenters[ @language ]
|
141
|
+
@indenters_next_line = $diakonos.indenters_next_line[ @language ]
|
142
|
+
@unindenters = $diakonos.unindenters[ @language ]
|
143
|
+
@preventers = @settings[ "lang.#{@language}.indent.preventers" ]
|
144
|
+
@closers = $diakonos.closers[ @language ] || Hash.new
|
145
|
+
@auto_indent = @settings[ "lang.#{@language}.indent.auto" ]
|
146
|
+
@indent_size = ( @settings[ "lang.#{@language}.indent.size" ] || 4 )
|
147
|
+
@indent_roundup = @settings[ "lang.#{@language}.indent.roundup" ].nil? ? true : @settings[ "lang.#{@language}.indent.roundup" ]
|
148
|
+
@indent_closers = @settings[ "lang.#{@language}.indent.closers" ].nil? ? false : @settings[ "lang.#{@language}.indent.closers" ]
|
149
|
+
@default_formatting = ( @settings[ "lang.#{@language}.format.default" ] || Curses::A_NORMAL )
|
150
|
+
@selection_formatting = ( @settings[ "lang.#{@language}.format.selection" ] || Curses::A_REVERSE )
|
151
|
+
@indent_ignore_charset = ( @settings[ "lang.#{@language}.indent.ignore.charset" ] || "" )
|
152
|
+
@tab_size = ( @settings[ "lang.#{@language}.tabsize" ] || DEFAULT_TAB_SIZE )
|
153
|
+
end
|
154
|
+
|
155
|
+
def [] ( arg )
|
156
|
+
@lines[ arg ]
|
157
|
+
end
|
158
|
+
|
159
|
+
def == (other)
|
160
|
+
return false if other.nil?
|
161
|
+
@name == other.name
|
162
|
+
end
|
163
|
+
|
164
|
+
def length
|
165
|
+
@lines.length
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_a
|
169
|
+
@lines.dup
|
170
|
+
end
|
171
|
+
|
172
|
+
def modified?
|
173
|
+
@modified
|
174
|
+
end
|
175
|
+
|
176
|
+
def nice_name
|
177
|
+
@name || @settings[ "status.unnamed_str" ]
|
178
|
+
end
|
179
|
+
|
180
|
+
def replace_char( c )
|
181
|
+
row = @last_row
|
182
|
+
col = @last_col
|
183
|
+
take_snapshot TYPING
|
184
|
+
@lines[ row ][ col ] = c
|
185
|
+
set_modified
|
186
|
+
end
|
187
|
+
|
188
|
+
def insert_char( c )
|
189
|
+
row = @last_row
|
190
|
+
col = @last_col
|
191
|
+
take_snapshot( TYPING )
|
192
|
+
line = @lines[ row ]
|
193
|
+
@lines[ row ] = line[ 0...col ] + c.chr + line[ col..-1 ]
|
194
|
+
set_modified
|
195
|
+
end
|
196
|
+
|
197
|
+
def insert_string( str )
|
198
|
+
row = @last_row
|
199
|
+
col = @last_col
|
200
|
+
take_snapshot( TYPING )
|
201
|
+
line = @lines[ row ]
|
202
|
+
@lines[ row ] = line[ 0...col ] + str + line[ col..-1 ]
|
203
|
+
set_modified
|
204
|
+
end
|
205
|
+
|
206
|
+
def surround( text, parenthesis )
|
207
|
+
pattern, pair = @surround_pairs.select { |r, p| parenthesis =~ r }.to_a[ 0 ]
|
208
|
+
|
209
|
+
if pair.nil?
|
210
|
+
$diakonos.set_iline "No matching parentheses pair found."
|
211
|
+
nil
|
212
|
+
else
|
213
|
+
pair.map! do |paren|
|
214
|
+
parenthesis.gsub( pattern, paren )
|
215
|
+
end
|
216
|
+
pair[ 0 ] + text.join( "\n" ) + pair[ 1 ]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def join_lines_upward( row = @last_row, strip = DONT_STRIP_LINE )
|
221
|
+
return false if row == 0
|
222
|
+
|
223
|
+
take_snapshot
|
224
|
+
|
225
|
+
line = @lines.delete_at( row )
|
226
|
+
old_line = @lines[ row-1 ]
|
227
|
+
|
228
|
+
new_x_pos = old_line.length
|
229
|
+
|
230
|
+
if strip
|
231
|
+
line.strip!
|
232
|
+
|
233
|
+
# Only prepend a space if the line above isn't empty.
|
234
|
+
if ! old_line.strip.empty?
|
235
|
+
line = ' ' + line
|
236
|
+
new_x_pos += 1
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
@lines[ row-1 ] << line
|
241
|
+
|
242
|
+
cursor_to( row-1, new_x_pos )
|
243
|
+
|
244
|
+
set_modified
|
245
|
+
end
|
246
|
+
|
247
|
+
def join_lines( row = @last_row, strip = DONT_STRIP_LINE )
|
248
|
+
take_snapshot( TYPING )
|
249
|
+
next_line = @lines.delete_at( row + 1 )
|
250
|
+
return false if next_line.nil?
|
251
|
+
|
252
|
+
if strip
|
253
|
+
next_line = ' ' + next_line.strip
|
254
|
+
end
|
255
|
+
@lines[ row ] << next_line
|
256
|
+
set_modified
|
257
|
+
end
|
258
|
+
|
259
|
+
def close_code
|
260
|
+
line = @lines[ @last_row ]
|
261
|
+
@closers.each_value do |h|
|
262
|
+
h[ :regexp ] =~ line
|
263
|
+
lm = Regexp.last_match
|
264
|
+
if lm
|
265
|
+
str = case h[ :closer ]
|
266
|
+
when String
|
267
|
+
if lm[ 1 ].nil?
|
268
|
+
h[ :closer ]
|
269
|
+
else
|
270
|
+
lm[ 1 ].gsub(
|
271
|
+
Regexp.new( "(#{ Regexp.escape( lm[1] ) })" ),
|
272
|
+
h[ :closer ]
|
273
|
+
)
|
274
|
+
end
|
275
|
+
when Proc
|
276
|
+
h[ :closer ].call( lm ).to_s
|
277
|
+
end
|
278
|
+
r, c = @last_row, @last_col
|
279
|
+
paste str, !TYPING, @indent_closers
|
280
|
+
cursor_to r, c
|
281
|
+
if /%_/ === str
|
282
|
+
find [/%_/], direction: :down, replacement: '', auto_choice: CHOICE_YES_AND_STOP
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def collapse_whitespace
|
289
|
+
if selection_mark
|
290
|
+
remove_selection DONT_DISPLAY
|
291
|
+
end
|
292
|
+
|
293
|
+
line = @lines[ @last_row ]
|
294
|
+
head = line[ 0...@last_col ]
|
295
|
+
tail = line[ @last_col..-1 ]
|
296
|
+
new_head = head.sub( /\s+$/, '' )
|
297
|
+
new_line = new_head + tail.sub( /^\s+/, ' ' )
|
298
|
+
if new_line != line
|
299
|
+
take_snapshot( TYPING )
|
300
|
+
@lines[ @last_row ] = new_line
|
301
|
+
cursor_to( @last_row, @last_col - ( head.length - new_head.length ) )
|
302
|
+
set_modified
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def columnize( delimiter = /=>?|:|,/, num_spaces_padding = 1 )
|
307
|
+
take_snapshot
|
308
|
+
|
309
|
+
lines = self.selected_lines
|
310
|
+
column_width = 0
|
311
|
+
lines.each do |line|
|
312
|
+
pos = ( line =~ delimiter )
|
313
|
+
if pos
|
314
|
+
column_width = [ pos, column_width ].max
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
padding = ' ' * num_spaces_padding
|
319
|
+
one_modified = false
|
320
|
+
|
321
|
+
lines.each do |line|
|
322
|
+
old_line = line.dup
|
323
|
+
if line =~ /^(.+?)(#{delimiter.source})(.*)$/
|
324
|
+
pre = $1
|
325
|
+
del = $2
|
326
|
+
post = $3
|
327
|
+
if pre !~ /\s$/
|
328
|
+
del = " #{del}"
|
329
|
+
end
|
330
|
+
if post !~ /^\s/
|
331
|
+
del = "#{del} "
|
332
|
+
end
|
333
|
+
del.sub!( /^\s+/, ' ' * num_spaces_padding )
|
334
|
+
del.sub!( /\s+$/, ' ' * num_spaces_padding )
|
335
|
+
line.replace( ( "%-#{column_width}s" % pre ) + del + post )
|
336
|
+
end
|
337
|
+
one_modified ||= ( line != old_line )
|
338
|
+
end
|
339
|
+
|
340
|
+
if one_modified
|
341
|
+
set_modified
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def comment_out
|
346
|
+
take_snapshot
|
347
|
+
|
348
|
+
one_modified = false
|
349
|
+
closer = @settings[ "lang.#{@language}.comment_close_string" ].to_s
|
350
|
+
|
351
|
+
self.selected_lines.each do |line|
|
352
|
+
next if line.strip.empty?
|
353
|
+
old_line = line.dup
|
354
|
+
line.gsub!( /^(\s*)/, "\\1" + @settings[ "lang.#{@language}.comment_string" ].to_s )
|
355
|
+
if ! closer.empty? && line !~ /#{Regexp.escape(closer)}$/
|
356
|
+
line << closer
|
357
|
+
end
|
358
|
+
one_modified ||= ( line != old_line )
|
359
|
+
end
|
360
|
+
|
361
|
+
if one_modified
|
362
|
+
set_modified
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def uncomment
|
367
|
+
take_snapshot
|
368
|
+
comment_string = Regexp.escape( @settings[ "lang.#{@language}.comment_string" ].to_s )
|
369
|
+
comment_close_string = Regexp.escape( @settings[ "lang.#{@language}.comment_close_string" ].to_s )
|
370
|
+
one_modified = false
|
371
|
+
self.selected_lines.each do |line|
|
372
|
+
old_line = line.dup
|
373
|
+
comment_regexp = /^(\s*)#{comment_string}/
|
374
|
+
line.gsub!( comment_regexp, "\\1" )
|
375
|
+
if line !~ comment_regexp
|
376
|
+
line.gsub!( /#{comment_close_string}$/, '' )
|
377
|
+
end
|
378
|
+
one_modified ||= ( line != old_line )
|
379
|
+
end
|
380
|
+
if one_modified
|
381
|
+
set_modified
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
def carriage_return
|
386
|
+
take_snapshot
|
387
|
+
row = @last_row
|
388
|
+
col = @last_col
|
389
|
+
@lines = @lines[ 0...row ] +
|
390
|
+
[ @lines[ row ][ 0...col ] ] +
|
391
|
+
[ @lines[ row ][ col..-1 ] ] +
|
392
|
+
@lines[ (row+1)..-1 ]
|
393
|
+
cursor_to( row + 1, 0 )
|
394
|
+
if @auto_indent
|
395
|
+
parsed_indent undoable: false
|
396
|
+
end
|
397
|
+
set_modified
|
398
|
+
end
|
399
|
+
|
400
|
+
def line_at( y )
|
401
|
+
row = @top_line + y
|
402
|
+
if row < 0
|
403
|
+
nil
|
404
|
+
else
|
405
|
+
@lines[ row ]
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def current_line
|
410
|
+
@lines[ @last_row ]
|
411
|
+
end
|
412
|
+
|
413
|
+
# Returns true iff the given column, x, is less than the length of the given line, y.
|
414
|
+
def in_line( x, y )
|
415
|
+
x + @left_column < line_at( y ).length
|
416
|
+
end
|
417
|
+
|
418
|
+
# Translates the window column, x, to a buffer-relative column index.
|
419
|
+
def column_of( x )
|
420
|
+
@left_column + x
|
421
|
+
end
|
422
|
+
|
423
|
+
# Translates the window row, y, to a buffer-relative row index.
|
424
|
+
def row_of( y )
|
425
|
+
@top_line + y
|
426
|
+
end
|
427
|
+
|
428
|
+
# Returns nil if the row is off-screen.
|
429
|
+
def row_to_y( row )
|
430
|
+
return nil if row.nil?
|
431
|
+
y = row - @top_line
|
432
|
+
y = nil if ( y < 0 ) || ( y > @top_line + $diakonos.main_window_height - 1 )
|
433
|
+
y
|
434
|
+
end
|
435
|
+
|
436
|
+
# Returns nil if the column is off-screen.
|
437
|
+
def column_to_x( col )
|
438
|
+
return nil if col.nil?
|
439
|
+
x = col - @left_column
|
440
|
+
x = nil if ( x < 0 ) || ( x > @left_column + Curses::cols - 1 )
|
441
|
+
x
|
442
|
+
end
|
443
|
+
|
444
|
+
def current_row
|
445
|
+
@last_row
|
446
|
+
end
|
447
|
+
|
448
|
+
def current_column
|
449
|
+
@last_col
|
450
|
+
end
|
451
|
+
|
452
|
+
def pan_view_to( left_column, do_display = DO_DISPLAY )
|
453
|
+
@left_column = [ left_column, 0 ].max
|
454
|
+
record_mark_start_and_end
|
455
|
+
display if do_display
|
456
|
+
end
|
457
|
+
|
458
|
+
# Returns the amount the view was actually panned.
|
459
|
+
def pan_view( x = 1, do_display = DO_DISPLAY )
|
460
|
+
old_left_column = @left_column
|
461
|
+
pan_view_to( @left_column + x, do_display )
|
462
|
+
@left_column - old_left_column
|
463
|
+
end
|
464
|
+
|
465
|
+
def pitch_view_to( new_top_line, do_pitch_cursor = DONT_PITCH_CURSOR, do_display = DO_DISPLAY )
|
466
|
+
old_top_line = @top_line
|
467
|
+
|
468
|
+
if new_top_line < 0
|
469
|
+
@top_line = 0
|
470
|
+
elsif new_top_line + $diakonos.main_window_height > @lines.length
|
471
|
+
@top_line = [ @lines.length - $diakonos.main_window_height, 0 ].max
|
472
|
+
else
|
473
|
+
@top_line = new_top_line
|
474
|
+
end
|
475
|
+
|
476
|
+
old_row = @last_row
|
477
|
+
old_col = @last_col
|
478
|
+
|
479
|
+
changed = ( @top_line - old_top_line )
|
480
|
+
if changed != 0 && do_pitch_cursor
|
481
|
+
@last_row += changed
|
482
|
+
end
|
483
|
+
|
484
|
+
height = [ $diakonos.main_window_height, @lines.length ].min
|
485
|
+
|
486
|
+
@last_row = NumberFitter.fit(
|
487
|
+
number: @last_row,
|
488
|
+
min: @top_line,
|
489
|
+
max: @top_line + height - 1,
|
490
|
+
)
|
491
|
+
|
492
|
+
if @last_row - @top_line < @settings["view.margin.y"]
|
493
|
+
@last_row = NumberFitter.fit(
|
494
|
+
number: @top_line + @settings["view.margin.y"],
|
495
|
+
min: @top_line,
|
496
|
+
max: @top_line + height - 1,
|
497
|
+
)
|
498
|
+
elsif @top_line + height - 1 - @last_row < @settings[ "view.margin.y" ]
|
499
|
+
@last_row = NumberFitter.fit(
|
500
|
+
number: @top_line + height - 1 - @settings[ "view.margin.y" ],
|
501
|
+
min: @top_line,
|
502
|
+
max: @top_line + height - 1,
|
503
|
+
)
|
504
|
+
end
|
505
|
+
|
506
|
+
@last_col = NumberFitter.fit(
|
507
|
+
number: @last_col,
|
508
|
+
min: @left_column,
|
509
|
+
max: [
|
510
|
+
@left_column + Curses::cols - 1,
|
511
|
+
@lines[@last_row].length
|
512
|
+
].min
|
513
|
+
)
|
514
|
+
|
515
|
+
@last_screen_y = @last_row - @top_line
|
516
|
+
@last_screen_x = tab_expanded_column( @last_col, @last_row ) - @left_column
|
517
|
+
|
518
|
+
record_mark_start_and_end
|
519
|
+
|
520
|
+
if changed != 0
|
521
|
+
if ! @auto_anchored && ! @changing_selection && selecting?
|
522
|
+
remove_selection DONT_DISPLAY
|
523
|
+
end
|
524
|
+
|
525
|
+
highlight_matches
|
526
|
+
if $diakonos.there_was_non_movement
|
527
|
+
$diakonos.push_cursor_state( old_top_line, old_row, old_col )
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
display if do_display
|
532
|
+
|
533
|
+
changed
|
534
|
+
end
|
535
|
+
|
536
|
+
# Returns the amount the view was actually pitched.
|
537
|
+
def pitch_view( y = 1, do_pitch_cursor = DONT_PITCH_CURSOR, do_display = DO_DISPLAY )
|
538
|
+
pitch_view_to( @top_line + y, do_pitch_cursor, do_display )
|
539
|
+
end
|
540
|
+
|
541
|
+
def wrap_paragraph
|
542
|
+
start_row = end_row = cursor_row = @last_row
|
543
|
+
cursor_col = @last_col
|
544
|
+
until start_row == 0 || @lines[ start_row - 1 ].strip == ''
|
545
|
+
start_row -= 1
|
546
|
+
end
|
547
|
+
until end_row == @lines.size || @lines[ end_row ].strip == ''
|
548
|
+
end_row += 1
|
549
|
+
end
|
550
|
+
|
551
|
+
lines = []
|
552
|
+
line = ''
|
553
|
+
words = @lines[ start_row...end_row ].join( ' ' ).scan( /\S+/ )
|
554
|
+
words.each do |word|
|
555
|
+
if word =~ /^[a-z']+[.!?]$/
|
556
|
+
word = "#{word} "
|
557
|
+
end
|
558
|
+
if line.length + word.length + 1 > ( @settings[ "lang.#{@language}.wrap_margin" ] || 80 )
|
559
|
+
lines << line.strip
|
560
|
+
line = ''
|
561
|
+
end
|
562
|
+
line << " #{word}"
|
563
|
+
end
|
564
|
+
line.strip!
|
565
|
+
if ! line.empty?
|
566
|
+
lines << line
|
567
|
+
end
|
568
|
+
if @lines[ start_row...end_row ] != lines
|
569
|
+
take_snapshot
|
570
|
+
@lines[ start_row...end_row ] = lines
|
571
|
+
set_modified
|
572
|
+
cursor_to start_row + lines.length, lines[-1].length
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
def context
|
577
|
+
retval = Array.new
|
578
|
+
row = @last_row
|
579
|
+
clevel = indentation_level( row )
|
580
|
+
while row > 0 && clevel < 0
|
581
|
+
row = row - 1
|
582
|
+
clevel = indentation_level( row )
|
583
|
+
end
|
584
|
+
clevel = 0 if clevel < 0
|
585
|
+
while row > 0
|
586
|
+
row = row - 1
|
587
|
+
line = @lines[ row ]
|
588
|
+
if ! line.strip.empty? && ( line !~ @settings[ "lang.#{@language}.context.ignore" ] )
|
589
|
+
level = indentation_level( row )
|
590
|
+
if level < clevel && level > -1
|
591
|
+
retval.unshift line
|
592
|
+
clevel = level
|
593
|
+
break if clevel == 0
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
retval
|
598
|
+
end
|
599
|
+
|
600
|
+
def set_type( type )
|
601
|
+
return false if type.nil?
|
602
|
+
configure( type )
|
603
|
+
display
|
604
|
+
true
|
605
|
+
end
|
606
|
+
|
607
|
+
def word_under_cursor
|
608
|
+
pos = word_under_cursor_pos
|
609
|
+
return if pos.nil?
|
610
|
+
|
611
|
+
col1 = pos[ 0 ][ 1 ]
|
612
|
+
col2 = pos[ 1 ][ 1 ]
|
613
|
+
@lines[ @last_row ][ col1...col2 ]
|
614
|
+
end
|
615
|
+
|
616
|
+
def word_under_cursor_pos( options = {} )
|
617
|
+
or_after = options[:or_after]
|
618
|
+
@lines[ @last_row ].scan( WORD_REGEXP ) do |match_text|
|
619
|
+
last_match = Regexp.last_match
|
620
|
+
if (
|
621
|
+
last_match.begin( 0 ) <= @last_col && @last_col < last_match.end( 0 ) ||
|
622
|
+
or_after && last_match.begin(0) > @last_col
|
623
|
+
)
|
624
|
+
return [
|
625
|
+
[ @last_row, last_match.begin( 0 ) ],
|
626
|
+
[ @last_row, last_match.end( 0 ) ],
|
627
|
+
]
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
nil
|
632
|
+
end
|
633
|
+
|
634
|
+
def word_before_cursor
|
635
|
+
word = nil
|
636
|
+
|
637
|
+
@lines[ @last_row ].scan( WORD_REGEXP ) do |match_text|
|
638
|
+
last_match = Regexp.last_match
|
639
|
+
if last_match.begin( 0 ) <= @last_col && @last_col <= last_match.end( 0 )
|
640
|
+
word = match_text
|
641
|
+
break
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
word
|
646
|
+
end
|
647
|
+
# TODO word_before_cursor_pos
|
648
|
+
|
649
|
+
# Returns an array of lines of the current paragraph.
|
650
|
+
def paragraph_under_cursor
|
651
|
+
( first, _ ), ( last, _ ) = paragraph_under_cursor_pos
|
652
|
+
@lines[ first..last ]
|
653
|
+
end
|
654
|
+
|
655
|
+
# Returns the coordinates of the first and last line of the current
|
656
|
+
# paragraph.
|
657
|
+
def paragraph_under_cursor_pos
|
658
|
+
if @lines[ @last_row ] =~ /^\s*$/
|
659
|
+
return [
|
660
|
+
[ @last_row, 0 ],
|
661
|
+
[ @last_row, @lines[ @last_row ].length - 1 ]
|
662
|
+
]
|
663
|
+
end
|
664
|
+
|
665
|
+
upper_boundary = 0
|
666
|
+
lower_boundary = @lines.size - 1
|
667
|
+
|
668
|
+
@last_row.downto( 0 ) do |i|
|
669
|
+
line = @lines[ i ]
|
670
|
+
if line =~ /^\s*$/
|
671
|
+
upper_boundary = i + 1
|
672
|
+
break
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
@last_row.upto( @lines.size - 1 ) do |i|
|
677
|
+
line = @lines[ i ]
|
678
|
+
if line =~ /^\s*$/
|
679
|
+
lower_boundary = i - 1
|
680
|
+
break
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
[
|
685
|
+
[ upper_boundary, 0 ],
|
686
|
+
[ lower_boundary, @lines[ lower_boundary ].length - 1 ]
|
687
|
+
]
|
688
|
+
end
|
689
|
+
# TODO paragraph_before_cursor(_pos)?
|
690
|
+
|
691
|
+
def words( filter_regexp = nil )
|
692
|
+
w = @lines.join( ' ' ).scan( WORD_REGEXP )
|
693
|
+
filter_regexp ? w.grep( filter_regexp ) : w
|
694
|
+
end
|
695
|
+
|
696
|
+
end
|
697
|
+
|
698
|
+
end
|