Class: Glimmer::Gladiator::File

Inherits:
Object
  • Object
show all
Includes:
Glimmer
Defined in:
lib/models/glimmer/gladiator/file.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = '', project_dir = nil) ⇒ File

Returns a new instance of File.



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/models/glimmer/gladiator/file.rb', line 30

def initialize(path='', project_dir=nil)
  raise "Not a file path: #{path}" if path.nil? || (!path.empty? && !::File.file?(path))
  @project_dir = project_dir
  @command_history = []
  @name = path.empty? ? 'Scratchpad' : ::File.basename(path)
  self.path = ::File.expand_path(path) unless path.empty?
  @top_pixel = 0
  @caret_position = 0
  @selection_count = 0
  @last_selection_count = 0
  @line_number = 1
  @init = nil
end

Instance Attribute Details

#caret_positionObject

Returns the value of attribute caret_position.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def caret_position
  @caret_position
end

#case_sensitiveObject

Returns the value of attribute case_sensitive.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def case_sensitive
  @case_sensitive
end

#display_pathObject

Returns the value of attribute display_path.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def display_path
  @display_path
end

#find_textObject

Returns the value of attribute find_text.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def find_text
  @find_text
end

#last_caret_positionObject

Returns the value of attribute last_caret_position.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def last_caret_position
  @last_caret_position
end

#last_selection_countObject

Returns the value of attribute last_selection_count.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def last_selection_count
  @last_selection_count
end

#line_numberObject

Returns the value of attribute line_number.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def line_number
  @line_number
end

#line_numbers_contentObject

Returns the value of attribute line_numbers_content.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def line_numbers_content
  @line_numbers_content
end

#line_positionObject

Returns the value of attribute line_position.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def line_position
  @line_position
end

#nameObject

Returns the value of attribute name.



28
29
30
# File 'lib/models/glimmer/gladiator/file.rb', line 28

def name
  @name
end

#pathObject

Returns the value of attribute path.



28
29
30
# File 'lib/models/glimmer/gladiator/file.rb', line 28

def path
  @path
end

#project_dirObject (readonly)

Returns the value of attribute project_dir.



28
29
30
# File 'lib/models/glimmer/gladiator/file.rb', line 28

def project_dir
  @project_dir
end

#replace_textObject

Returns the value of attribute replace_text.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def replace_text
  @replace_text
end

#selection_countObject

Returns the value of attribute selection_count.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def selection_count
  @selection_count
end

#top_pixelObject

Returns the value of attribute top_pixel.



27
28
29
# File 'lib/models/glimmer/gladiator/file.rb', line 27

def top_pixel
  @top_pixel
end

Instance Method Details

#backup_propertiesObject



253
254
255
256
257
# File 'lib/models/glimmer/gladiator/file.rb', line 253

def backup_properties
  [:find_text, :replace_text, :case_sensitive, :top_pixel, :caret_position, :selection_count].reduce({}) do |hash, property|
    hash.merge(property => send(property))
  end
end

#caret_position_for_caret_position_start_of_line(caret_position) ⇒ Object



775
776
777
# File 'lib/models/glimmer/gladiator/file.rb', line 775

def caret_position_for_caret_position_start_of_line(caret_position)
  caret_position_for_line_index(line_index_for_caret_position(caret_position))
end

#caret_position_for_line_index(line_index) ⇒ Object



769
770
771
772
773
# File 'lib/models/glimmer/gladiator/file.rb', line 769

def caret_position_for_line_index(line_index)
  cp = lines[0...line_index].join("\n").size
  cp += 1 if line_index > 0
  cp
end

#change_content!(value) ⇒ Object



307
308
309
310
311
# File 'lib/models/glimmer/gladiator/file.rb', line 307

def change_content!(value)
  self.dirty_content = value
  format_dirty_content_for_writing!(force: true) if value.to_s.include?("\r\n")
  update_line_number_from_caret_position(caret_position)
end

#childrenObject



812
813
814
# File 'lib/models/glimmer/gladiator/file.rb', line 812

def children
  []
end

#closeObject



325
326
327
328
329
330
331
# File 'lib/models/glimmer/gladiator/file.rb', line 325

def close
  @closed = true
  stop_filewatcher
  remove_all_observers
  initialize(path, project_dir)
  Command.clear(self)
end

#closed?Boolean

Returns:

  • (Boolean)


333
334
335
# File 'lib/models/glimmer/gladiator/file.rb', line 333

def closed?
  @closed
end

#command_in_progress?Boolean

Returns:

  • (Boolean)


321
322
323
# File 'lib/models/glimmer/gladiator/file.rb', line 321

def command_in_progress?
  @commmand_in_progress
end

#comment_line!Object



425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/models/glimmer/gladiator/file.rb', line 425

def comment_line!
  old_lines = lines
  return if old_lines.size < 1
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_index = line_index_for_caret_position(old_caret_position)
  old_caret_position_line_caret_position = caret_position_for_line_index(old_caret_position_line_index)
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  new_lines = lines
  delta = 0
  line_indices_for_selection(caret_position, selection_count).reverse.each do | the_line_index |
    delta = 0
    the_line = old_lines[the_line_index]
    return if the_line.nil?
    if the_line.strip.start_with?("#{single_line_comment_prefix} ")
      new_lines[the_line_index] = the_line.sub(/#{single_line_comment_prefix} /, '')
      # TODO single_line_comment_postfix if needed
      delta -= 2
    elsif the_line.strip.start_with?(single_line_comment_prefix)
      new_lines[the_line_index] = the_line.sub(/#{single_line_comment_prefix}/, '')
      # TODO single_line_comment_postfix if needed
      delta -= 1
    else
      new_lines[the_line_index] = "#{single_line_comment_prefix} #{the_line}"
      # TODO single_line_comment_postfix if needed
      delta += 2
    end
  end
  self.dirty_content = new_lines.join("\n")
  if old_selection_count.to_i > 0
    self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
    self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
  else
    new_caret_position = old_caret_position + delta
    new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
    self.caret_position = new_caret_position
    self.selection_count = 0
  end
end

#contentObject



295
296
297
# File 'lib/models/glimmer/gladiator/file.rb', line 295

def content
  dirty_content
end

#content=(value) ⇒ Object

to use for widget data-binding



300
301
302
303
304
305
# File 'lib/models/glimmer/gladiator/file.rb', line 300

def content=(value)
  value = value.gsub("\t", '  ')
  if dirty_content != value
    Command.do(self, :change_content!, value)
  end
end

#copyObject



683
684
685
# File 'lib/models/glimmer/gladiator/file.rb', line 683

def copy
  Clipboard.copy(selected_text)
end

#current_lineObject



401
402
403
# File 'lib/models/glimmer/gladiator/file.rb', line 401

def current_line
  lines[line_number - 1]
end

#current_line_indentationObject



397
398
399
# File 'lib/models/glimmer/gladiator/file.rb', line 397

def current_line_indentation
  current_line.to_s.match(/^(\s+)/).to_a[1].to_s
end

#cut!Object



678
679
680
681
# File 'lib/models/glimmer/gladiator/file.rb', line 678

def cut!
  Clipboard.copy(selected_text)
  delete!
end

#delete!Object

deletes content that is highlighted



670
671
672
673
674
675
676
# File 'lib/models/glimmer/gladiator/file.rb', line 670

def delete!
  new_dirty_content = dirty_content
  new_dirty_content[caret_position...(caret_position + selection_count)] = ''
  old_caret_position = caret_position
  self.dirty_content = new_dirty_content
  self.caret_position = old_caret_position
end

#dirty_contentObject



277
278
279
280
# File 'lib/models/glimmer/gladiator/file.rb', line 277

def dirty_content
  init_content
  @dirty_content
end

#dirty_content=(the_content) ⇒ Object



282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/models/glimmer/gladiator/file.rb', line 282

def dirty_content=(the_content)
  # TODO set partial dirty content by line(s) for enhanced performance
  @dirty_content = the_content
  old_caret_position = caret_position
  old_top_pixel = top_pixel
  
  notify_observers(:content)
  if @formatting_dirty_content_for_writing
    self.caret_position = old_caret_position
    self.top_pixel = old_top_pixel
  end
end

#duplicate_line!Object



535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'lib/models/glimmer/gladiator/file.rb', line 535

def duplicate_line!
  new_lines = lines
  old_lines = lines
  return if old_lines.size < 1
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_index = line_index_for_caret_position(old_caret_position)
  old_caret_position_line_caret_position = caret_position_for_caret_position_start_of_line(old_caret_position_line_index)
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  the_line_indices = line_indices_for_selection(caret_position, selection_count)
  the_lines = lines_for_selection(caret_position, selection_count)
  delta = the_lines.join("\n").size + 1
  the_lines.each_with_index do |the_line, i|
    new_lines.insert(the_line_indices.first + i, the_line)
  end
  self.dirty_content = new_lines.join("\n")
  if old_selection_count.to_i > 0
    self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
    self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
  else
    self.caret_position = old_caret_position + delta
    self.selection_count = 0
  end
end

#endObject



643
644
645
646
# File 'lib/models/glimmer/gladiator/file.rb', line 643

def end
  self.line_number = lines.size
  self.selection_count = 0
end

#end_caret_position_line_index(caret_position, selection_count) ⇒ Object



791
792
793
794
795
# File 'lib/models/glimmer/gladiator/file.rb', line 791

def end_caret_position_line_index(caret_position, selection_count)
  end_caret_position = caret_position + selection_count.to_i
  end_caret_position -= 1 if dirty_content[end_caret_position - 1] == "\n"
  end_line_index = line_index_for_caret_position(end_caret_position)
end

#end_commandObject



317
318
319
# File 'lib/models/glimmer/gladiator/file.rb', line 317

def end_command
  @commmand_in_progress = false
end

#end_of_lineObject



653
654
655
656
# File 'lib/models/glimmer/gladiator/file.rb', line 653

def end_of_line
  self.caret_position = caret_position_for_line_index(self.line_number) - 1
  self.selection_count = 0
end

#ensure_find_nextObject



608
609
610
611
# File 'lib/models/glimmer/gladiator/file.rb', line 608

def ensure_find_next
  return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
  find_next unless found_text?(self.caret_position)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


820
821
822
# File 'lib/models/glimmer/gladiator/file.rb', line 820

def eql?(other)
  self.path.eql?(other&.path)
end

#extensionObject



44
45
46
# File 'lib/models/glimmer/gladiator/file.rb', line 44

def extension
  path.split('.').last if path.to_s.include?('.')
end

#find_nextObject



560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/models/glimmer/gladiator/file.rb', line 560

def find_next
  return if find_text.to_s.empty?
  all_lines = lines
  the_line_index = line_index_for_caret_position(caret_position)
  line_position = line_position_for_caret_position(caret_position)
  found = found_text?(caret_position)
  2.times do |i|
    rotation = the_line_index
    all_lines.rotate(rotation).each_with_index do |the_line, the_index|
      the_index = (the_index + rotation)%all_lines.size
      start_position = 0
      start_position = line_position + find_text.to_s.size if i == 0 && the_index == the_line_index && found_text?(caret_position)
      text_to_find_in = the_line[start_position..-1]
      occurrence_index = case_sensitive ? text_to_find_in&.index(find_text.to_s) : text_to_find_in&.downcase&.index(find_text.to_s.downcase)
      if occurrence_index
        self.caret_position = caret_position_for_line_index(the_index) + start_position + occurrence_index
        self.selection_count = find_text.to_s.size
        return
      end
    end
  end
end

#find_previousObject



583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
# File 'lib/models/glimmer/gladiator/file.rb', line 583

def find_previous
  return if find_text.to_s.empty?
  all_lines = lines
  the_line_index = line_index_for_caret_position(caret_position)
  line_position = line_position_for_caret_position(caret_position)
  2.times do |i|
    rotation = - the_line_index - 1 + all_lines.size
    all_lines.reverse.rotate(rotation).each_with_index do |the_line, the_index|
      the_index = all_lines.size - 1 - (the_index + rotation)%all_lines.size
      if the_index == the_line_index
        start_position = i > 0 ? 0 : (the_line.size - line_position)
      else
        start_position = 0
      end
      text_to_find_in = the_line.downcase.reverse[start_position...the_line.size].to_s
      occurrence_index = text_to_find_in.index(find_text.to_s.downcase.reverse)
      if occurrence_index
        self.caret_position = caret_position_for_line_index(the_index) + (the_line.size - (start_position + occurrence_index + find_text.to_s.size))
        self.selection_count = find_text.to_s.size
        return
      end
    end
  end
end

#format_dirty_content_for_writing!(force: false) ⇒ Object



376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/models/glimmer/gladiator/file.rb', line 376

def format_dirty_content_for_writing!(force: false)
  return if !force && @commmand_in_progress
  new_dirty_content = dirty_content.to_s.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
  new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
  if new_dirty_content != self.dirty_content
    @formatting_dirty_content_for_writing = true
    caret_position_diff = dirty_content.to_s.size - new_dirty_content.size
    self.dirty_content = new_dirty_content
    self.caret_position = caret_position - caret_position_diff
    @formatting_dirty_content_for_writing = false
  end
end

#found_text?(caret_position) ⇒ Boolean

Returns:

  • (Boolean)


613
614
615
# File 'lib/models/glimmer/gladiator/file.rb', line 613

def found_text?(caret_position)
  dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
end

#generate_display_pathObject



229
230
231
232
# File 'lib/models/glimmer/gladiator/file.rb', line 229

def generate_display_path
  return if @path.empty?
  @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
end

#hashObject



824
825
826
# File 'lib/models/glimmer/gladiator/file.rb', line 824

def hash
  self.path.hash
end

#homeObject



638
639
640
641
# File 'lib/models/glimmer/gladiator/file.rb', line 638

def home
  self.line_number = 1
  self.selection_count = 0
end

#indent!Object



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/models/glimmer/gladiator/file.rb', line 465

def indent!
  new_lines = lines
  old_lines = lines
  return if old_lines.size < 1
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_index = line_index_for_caret_position(old_caret_position)
  old_caret_position_line_caret_position = caret_position_for_line_index(old_caret_position_line_index)
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  delta = 2
  line_indices_for_selection(caret_position, selection_count).each do |the_line_index|
    the_line = old_lines[the_line_index]
    new_lines[the_line_index] = "  #{the_line}"
  end
  old_caret_position = self.caret_position
  self.dirty_content = new_lines.join("\n")
  if old_selection_count.to_i > 0
    self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
    self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
  else
    self.caret_position = old_caret_position + delta
    self.selection_count = 0
  end
end

#init_contentObject

TODO support: def single_line_comment_postfix



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/models/glimmer/gladiator/file.rb', line 182

def init_content
  unless @init
    @init = true
    begin
      # test read dirty content
      observe(self, :dirty_content) do
        line_count = lines.empty? ? 1 : lines.size
        lines_text_size = [line_count.to_s.size, 4].max
        old_top_pixel = top_pixel
        self.line_numbers_content = line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
        self.top_pixel = old_top_pixel
      end
      the_dirty_content = read_dirty_content
      the_dirty_content.split("\n") # test that it is not a binary file (crashes to rescue block otherwise)
      self.dirty_content = the_dirty_content
      observe(self, :caret_position) do |new_caret_position|
        update_line_number_from_caret_position(new_caret_position)
      end
      observe(self, :line_number) do |new_line_number|
        line_index = line_number - 1
        new_caret_position = caret_position_for_line_index(line_index)
        current_caret_position = caret_position
        line_index_for_new_caret_position = line_index_for_caret_position(new_caret_position)
        line_index_for_current_caret_position = line_index_for_caret_position(current_caret_position)
        self.caret_position = new_caret_position unless (current_caret_position && line_index_for_new_caret_position == line_index_for_current_caret_position)
      end
    rescue # in case of a binary file
      stop_filewatcher
    end
  end
end

#insert_new_line!Object



417
418
419
420
421
422
423
# File 'lib/models/glimmer/gladiator/file.rb', line 417

def insert_new_line!
  the_lines = lines
  the_lines[line_number...line_number] = [current_line_indentation]
  self.dirty_content = the_lines.join("\n")
  self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
  self.selection_count = 0
end

#kill_line!Object



522
523
524
525
526
527
528
529
530
531
532
533
# File 'lib/models/glimmer/gladiator/file.rb', line 522

def kill_line!
  new_lines = lines
  return if new_lines.size < 1
  line_indices = line_indices_for_selection(caret_position, selection_count)
  new_lines = new_lines[0...line_indices.first] + new_lines[(line_indices.last+1)...new_lines.size]
  old_caret_position = self.caret_position
  old_line_index = self.line_number - 1
  line_position = line_position_for_caret_position(old_caret_position)
  self.dirty_content = "#{new_lines.join("\n")}\n"
  self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
  self.selection_count = 0
end

#languageObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/models/glimmer/gladiator/file.rb', line 48

def language
  # TODO consider using Rouge::Lexer.guess_by_filename instead and perhaps guess_by_source when it fails
  return 'ruby' if scratchpad?
  return 'ruby' if path.to_s.end_with?('Gemfile') || path.to_s.end_with?('Rakefile')
  return 'ruby' if dirty_content.start_with?('#!/usr/bin/env ruby') || dirty_content.start_with?('#!/usr/bin/env jruby')
  return 'yaml' if path.to_s.end_with?('Gemfile.lock')
  return 'shell' if extension.nil? && path.to_s.include?('/bin/')
  return 'make' if path.to_s.end_with?('Makefile') || path.to_s.end_with?('makefile') || path.to_s.end_with?('GNUmakefile')
  case extension
  # TODO extract case statement to an external config file
  when 'c', 'h'
    'c'
  when 'cpp', 'cc', 'C', 'cxx', 'c++', 'hpp', 'hh', 'H', 'hxx', 'h++'
    'cpp'
  when 'cr'
    'crystal'
  when 'cs'
    'csharp'
  when 'css'
    'css'
  when 'conf'
    'conf'
  when 'coffee'
    'coffeescript'
  when 'eex', 'leex', 'heex'
    'eex' # embedded elixir
  when 'erb'
    'erb'
  when 'ex', 'exs'
    'elixir'
  when 'feature'
    'gherkin'
  when 'gradle'
    'gradle'
  when 'haml'
    'haml'
  when 'html'
    'html'
  when 'ini'
    'ini'
  when 'java'
    'java'
  when 'js', 'cjs', 'mjs', 'es6', 'es'
    'javascript'
  when 'json'
    'json'
  when 'jsp'
    'jsp'
  when 'jsx'
    'jsx'
  when 'kt', 'ktm', 'kts'
    'kotlin'
  when 'lisp', 'cl', 'el', 'asd'
    'lisp'
  when 'md', 'markdown'
    'markdown'
  when 'patch'
    'diff'
  when 'pl'
    'perl'
  when 'plist'
    'plist'
  when 'pp'
    'puppet'
  when 'properties'
    'properties'
  when 'ps'
    'postscript'
  when 'ps1'
    'powershell'
  when 'py'
    'python'
  when 'rs'
    'rust'
  when 'rb', 'rbw', 'rake', 'gemspec'
    'ruby'
  when 'sass'
    'sass'
  when 'scm', 'sps', 'sls', 'sld'
    'scheme'
  when 'scss'
    'scss'
  when 'sh'
    'shell'
  when 'sql'
    'sql'
  when 'tcl'
    'tcl'
  when 'ts'
    'typescript'
  when 'tsx'
    'tsx'
  when 'txt', nil
    'plaintext'
  when 'yaml', 'yml'
    'yaml'
  when 'xml'
    'xml'
  else
    'plaintext'
  end
end

#line_caret_positions_for_selection(caret_position, selection_count) ⇒ Object



786
787
788
789
# File 'lib/models/glimmer/gladiator/file.rb', line 786

def line_caret_positions_for_selection(caret_position, selection_count)
  line_indices = line_indices_for_selection(caret_position, selection_count)
  line_caret_positions = line_indices.map { |line_index| caret_position_for_line_index(line_index) }.to_a
end

#line_for_caret_position(caret_position) ⇒ Object



761
762
763
# File 'lib/models/glimmer/gladiator/file.rb', line 761

def line_for_caret_position(caret_position)
  lines[line_index_for_caret_position(caret_position.to_i)]
end

#line_index_for_caret_position(caret_position) ⇒ Object



765
766
767
# File 'lib/models/glimmer/gladiator/file.rb', line 765

def line_index_for_caret_position(caret_position)
  dirty_content[0...caret_position.to_i].count("\n")
end

#line_indices_for_selection(caret_position, selection_count) ⇒ Object



802
803
804
805
806
807
808
809
810
# File 'lib/models/glimmer/gladiator/file.rb', line 802

def line_indices_for_selection(caret_position, selection_count)
  start_line_index = line_index_for_caret_position(caret_position)
  if selection_count.to_i > 0
    end_line_index = end_caret_position_line_index(caret_position, selection_count)
  else
    end_line_index = start_line_index
  end
  (start_line_index..end_line_index).to_a
end

#line_position_for_caret_position(caret_position) ⇒ Object

position within line containing “caret position” (e.g. for caret position 5 in 1st line, they match as 5, for 15 in line 2 with line 1 having 10 characters, line position is 4) TODO consider renaming to line_character_position_for_caret_position



781
782
783
784
# File 'lib/models/glimmer/gladiator/file.rb', line 781

def line_position_for_caret_position(caret_position)
  caret_position = caret_position.to_i
  caret_position - caret_position_for_caret_position_start_of_line(caret_position)
end

#linesObject



753
754
755
756
757
758
759
# File 'lib/models/glimmer/gladiator/file.rb', line 753

def lines
  need_padding = dirty_content.to_s.end_with?("\n")
  splittable_content = need_padding ? "#{dirty_content} " : dirty_content
  the_lines = splittable_content.split("\n")
  the_lines[-1] = the_lines[-1].strip if need_padding
  the_lines
end

#lines_for_selection(caret_position, selection_count) ⇒ Object



797
798
799
800
# File 'lib/models/glimmer/gladiator/file.rb', line 797

def lines_for_selection(caret_position, selection_count)
  line_indices = line_indices_for_selection(caret_position, selection_count)
  lines[line_indices.first..line_indices.last]
end

#move_down!Object



725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
# File 'lib/models/glimmer/gladiator/file.rb', line 725

def move_down!
  old_lines = lines
  return if old_lines.size < 2
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_caret_position = caret_position_for_caret_position_start_of_line(old_caret_position)
  old_caret_position_line_position = old_caret_position - old_caret_position_line_caret_position
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  new_lines = lines
  the_line_indices = line_indices_for_selection(caret_position, selection_count)
  the_lines = lines_for_selection(caret_position, selection_count)
  new_line_index = [the_line_indices.first + 1, new_lines.size - 1].min
  new_lines[the_line_indices.first..the_line_indices.last] = []
  new_lines[new_line_index...new_line_index] = the_lines
  self.dirty_content = new_lines.join("\n")
  self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
  self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
end

#move_up!Object



706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'lib/models/glimmer/gladiator/file.rb', line 706

def move_up!
  old_lines = lines
  return if old_lines.size < 2
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_caret_position = caret_position_for_caret_position_start_of_line(old_caret_position)
  old_caret_position_line_position = old_caret_position - old_caret_position_line_caret_position
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  new_lines = lines
  the_line_indices = line_indices_for_selection(caret_position, selection_count)
  the_lines = lines_for_selection(caret_position, selection_count)
  new_line_index = [the_line_indices.first - 1, 0].max
  new_lines[the_line_indices.first..the_line_indices.last] = []
  new_lines[new_line_index...new_line_index] = the_lines
  self.dirty_content = new_lines.join("\n")
  self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
  self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
end

#outdent!Object



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/models/glimmer/gladiator/file.rb', line 490

def outdent!
  new_lines = lines
  old_lines = lines
  return if old_lines.size < 1
  old_selection_count = self.selection_count
  old_caret_position = self.caret_position
  old_caret_position_line_index = line_index_for_caret_position(old_caret_position)
  old_caret_position_line_caret_position = caret_position_for_line_index(old_caret_position_line_index)
  old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
  delta = 0
  line_indices_for_selection(caret_position, selection_count).each do |the_line_index|
    the_line = old_lines[the_line_index]
    if the_line.to_s.start_with?('  ')
      new_lines[the_line_index] = the_line.sub(/  /, '')
      delta = -2
    elsif the_line&.start_with?(' ')
      new_lines[the_line_index] = the_line.sub(/ /, '')
      delta = -1
    end
  end
  self.dirty_content = new_lines.join("\n")
  if old_selection_count.to_i > 0
    self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
    self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
  else
    new_caret_position = old_caret_position + delta
    new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
    self.caret_position = new_caret_position
    self.selection_count = 0
  end
end

#page_downObject



633
634
635
636
# File 'lib/models/glimmer/gladiator/file.rb', line 633

def page_down
  self.line_number = [(self.line_number + 15), lines.size].min
  self.selection_count = 0
end

#page_upObject



628
629
630
631
# File 'lib/models/glimmer/gladiator/file.rb', line 628

def page_up
  self.line_number = [(self.line_number - 15), 1].max
  self.selection_count = 0
end

#paste!Object



687
688
689
690
691
692
693
694
695
# File 'lib/models/glimmer/gladiator/file.rb', line 687

def paste!
  new_dirty_content = dirty_content
  pasted_text = Clipboard.paste
  new_dirty_content[caret_position...(caret_position + selection_count)] = pasted_text
  old_caret_position = caret_position
  self.dirty_content = new_dirty_content
  self.caret_position = old_caret_position + pasted_text.to_s.size
  self.selection_count = 0
end

#prefix_new_line!Object



409
410
411
412
413
414
415
# File 'lib/models/glimmer/gladiator/file.rb', line 409

def prefix_new_line!
  the_lines = lines
  the_lines[line_number-1...line_number-1] = [current_line_indentation]
  self.dirty_content = the_lines.join("\n")
  self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
  self.selection_count = 0
end

#read_dirty_contentObject



337
338
339
# File 'lib/models/glimmer/gladiator/file.rb', line 337

def read_dirty_content
  path.empty? ? '' : ::File.read(path)
end

#remove!Object



405
406
407
# File 'lib/models/glimmer/gladiator/file.rb', line 405

def remove!
  FileUtils.rm_rf(path) unless scratchpad?
end

#replace_next!Object



617
618
619
620
621
622
623
624
625
626
# File 'lib/models/glimmer/gladiator/file.rb', line 617

def replace_next!
  return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
  ensure_find_next
  new_dirty_content = dirty_content
  new_dirty_content[caret_position, find_text.size] = replace_text.to_s
  self.dirty_content = new_dirty_content
  find_next
  find_next if replace_text.to_s.include?(find_text) && !replace_text.to_s.start_with?(find_text)
  write_dirty_content
end

#restore_properties(properties_hash) ⇒ Object



259
260
261
262
263
264
# File 'lib/models/glimmer/gladiator/file.rb', line 259

def restore_properties(properties_hash)
  return if properties_hash[:caret_position] == 0 && properties_hash[:selection_count] == 0 && properties_hash[:find_text].nil? && properties_hash[:replace_text].nil? && properties_hash[:top_pixel] == 0 && properties_hash[:case_sensitive].nil?
  properties_hash.each do |property, value|
    send("#{property}=", value)
  end
end

#runObject



744
745
746
747
748
749
750
751
# File 'lib/models/glimmer/gladiator/file.rb', line 744

def run
  if scratchpad?
    load scratchpad_file
  else
    write_dirty_content
    load path
  end
end

#scratchpad?Boolean

Returns:

  • (Boolean)


243
244
245
# File 'lib/models/glimmer/gladiator/file.rb', line 243

def scratchpad?
  path.to_s.empty? # TODO consider updating to set the .gladiator-scratchpad path directly
end

#scratchpad_fileObject



247
248
249
250
251
# File 'lib/models/glimmer/gladiator/file.rb', line 247

def scratchpad_file
  scratchpad_file = ::File.join(project_dir.path, '.gladiator-scratchpad')
  ::File.write(scratchpad_file, content)
  scratchpad_file
end

#select_allObject



697
698
699
700
# File 'lib/models/glimmer/gladiator/file.rb', line 697

def select_all
  self.caret_position = 0
  self.selection_count = dirty_content.to_s.size
end

#select_to_end_of_lineObject



664
665
666
667
# File 'lib/models/glimmer/gladiator/file.rb', line 664

def select_to_end_of_line
  self.caret_position = selection_count == 0 ? caret_position : caret_position + selection_count
  self.selection_count = (caret_position_for_line_index(self.line_number) - 1) - caret_position
end

#select_to_start_of_lineObject



658
659
660
661
662
# File 'lib/models/glimmer/gladiator/file.rb', line 658

def select_to_start_of_line
  old_caret_position = caret_position
  self.caret_position = caret_position_for_line_index(self.line_number - 1)
  self.selection_count = old_caret_position - caret_position
end

#selected_textObject



702
703
704
# File 'lib/models/glimmer/gladiator/file.rb', line 702

def selected_text
  dirty_content.to_s[caret_position, selection_count]
end

#single_line_comment_prefixObject



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/models/glimmer/gladiator/file.rb', line 151

def single_line_comment_prefix
  case language
  when 'c', 'cpp', 'csharp', 'gradle', 'java', 'javascript', 'jsx', 'kotlin', 'rust', 'typescript', 'tsx', 'sass', 'scss'
    '//'
  when 'crystal', 'conf', 'coffeescript', 'elixir', 'gherkin', 'ini', 'perl', 'puppet', 'properties', 'powershell', 'python', 'ruby', 'shell', 'tcl', 'yaml'
    '#'
  when 'css'
    '/*'
  when 'eex', 'leex', 'heex', 'erb', 'html', 'jsp', 'plist', 'xml'
    # TODO in the future, have .erb support `#` single line comment inside Ruby code scriptlets as opposed to scriptlet-free code
    '<!--'
  when 'haml'
    '/'
  when 'markdown'
    '<!---'
  when 'postscript'
    '%'
  when 'lisp', 'scheme'
    ';'
  when 'sql'
    '--'
  when 'json', 'diff', 'plaintext'
       nil
    nil
  else
    '#'
  end
end

#start_commandObject



313
314
315
# File 'lib/models/glimmer/gladiator/file.rb', line 313

def start_command
  @commmand_in_progress = true
end

#start_filewatcherObject



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/models/glimmer/gladiator/file.rb', line 341

def start_filewatcher
  return if scratchpad?
  @filewatcher ||= Filewatcher.new(@path)
  @filewatcher_thread ||= Thread.new(@filewatcher) do |fw|
    fw.watch do |filename, event|
      async_exec do
        begin
          self.dirty_content = read_dirty_content if read_dirty_content != dirty_content
        rescue StandardError, Errno::ENOENT
          # in case of a binary file
          stop_filewatcher
        end
      end
    end
  end
end

#start_of_lineObject



648
649
650
651
# File 'lib/models/glimmer/gladiator/file.rb', line 648

def start_of_line
  self.caret_position = caret_position_for_line_index(self.line_number - 1)
  self.selection_count = 0
end

#stop_filewatcherObject



358
359
360
361
362
363
364
# File 'lib/models/glimmer/gladiator/file.rb', line 358

def stop_filewatcher
  @filewatcher&.stop
  @filewatcher_thread&.kill
  @filewatcher_thread = nil
  @filewatcher&.finalize
  @filewatcher = nil
end

#to_sObject



816
817
818
# File 'lib/models/glimmer/gladiator/file.rb', line 816

def to_s
  path
end

#update_line_number_from_caret_position(new_caret_position) ⇒ Object



214
215
216
217
218
219
220
221
222
# File 'lib/models/glimmer/gladiator/file.rb', line 214

def update_line_number_from_caret_position(new_caret_position)
  new_line_number = line_index_for_caret_position(caret_position) + 1
  current_line_number = line_number
  unless (current_line_number && current_line_number == new_line_number)
    self.line_number = new_line_number
    # TODO check if the following line is needed
  end
  self.line_position = caret_position - caret_position_for_line_index(line_number - 1) + 1
end

#write_dirty_contentObject



366
367
368
369
370
371
372
373
374
# File 'lib/models/glimmer/gladiator/file.rb', line 366

def write_dirty_content
  # TODO write partial dirty content by line(s) for enhanced performance
  return if scratchpad? || !::File.exist?(path) || !::File.exists?(path) || read_dirty_content == dirty_content
  format_dirty_content_for_writing!
  ::File.write(path, dirty_content)
rescue StandardError, ArgumentError => e
  puts "Error in writing dirty content for #{path}"
  puts e.full_message
end

#write_raw_dirty_contentObject



389
390
391
392
393
394
395
# File 'lib/models/glimmer/gladiator/file.rb', line 389

def write_raw_dirty_content
  return if scratchpad? || !::File.exist?(path)
  ::File.write(path, dirty_content) if ::File.exists?(path)
rescue => e
  puts "Error in writing raw dirty content for #{path}"
  puts e.full_message
end