lib/textbringer/window.rb in textbringer-0.1.7 vs lib/textbringer/window.rb in textbringer-0.1.8
- old
+ new
@@ -46,13 +46,15 @@
Curses.constants.grep(/\AKEY_/).each do |name|
KEY_NAMES[Curses.const_get(name)] =
name.slice(/\AKEY_(.*)/, 1).downcase.intern
end
+ @@started = false
@@windows = []
@@current = nil
@@echo_area = nil
+ @@has_colors = false
def self.windows
@@windows
end
@@ -117,14 +119,46 @@
def self.echo_area
@@echo_area
end
+ def self.has_colors=(value)
+ @@has_colors = value
+ end
+
+ def self.has_colors?
+ @@has_colors
+ end
+
+ def self.colors
+ Curses.colors
+ end
+
+ def self.set_default_colors(fg, bg)
+ Curses.assume_default_colors(Color[fg], Color[bg])
+ Window.redraw
+ end
+
+ def self.load_faces
+ require_relative "faces/basic"
+ require_relative "faces/programming"
+ end
+
def self.start
+ if @@started
+ raise EditorError, "Already started"
+ end
Curses.init_screen
Curses.noecho
Curses.raw
+ Curses.nonl
+ self.has_colors = Curses.has_colors?
+ if has_colors?
+ Curses.start_color
+ Curses.use_default_colors
+ load_faces
+ end
begin
window =
Textbringer::Window.new(Window.lines - 1, Window.columns, 0, 0)
window.buffer = Buffer.new_buffer("*scratch*")
@@windows.push(window)
@@ -132,15 +166,22 @@
@@echo_area = Textbringer::EchoArea.new(1, Window.columns,
Window.lines - 1, 0)
Buffer.minibuffer.keymap = MINIBUFFER_LOCAL_MAP
@@echo_area.buffer = Buffer.minibuffer
@@windows.push(@@echo_area)
+ @@started = true
yield
ensure
+ @@windows.each do |win|
+ win.delete
+ end
+ @@windows.clear
Curses.echo
Curses.noraw
+ Curses.nl
Curses.close_screen
+ @@started = false
end
end
def self.redisplay
return if Window.current.has_input?
@@ -171,11 +212,12 @@
Curses.cols
end
def self.resize
@@windows.delete_if do |window|
- if !window.echo_area? && window.y > Window.lines - 4
+ if !window.echo_area? &&
+ window.y > Window.lines - CONFIG[:window_min_height]
window.delete
true
else
false
end
@@ -282,11 +324,11 @@
return "\e"
end
end
KEY_NAMES[key] || key
else
- key&.encode(Encoding::UTF_8)&.tr("\r", "\n")
+ key&.encode(Encoding::UTF_8)
end
end
def read_char_nonblock
@window.nodelay = true
@@ -327,10 +369,44 @@
ensure
@window.nodelay = false
end
end
+ def highlight
+ @highlight_on = {}
+ @highlight_off = {}
+ return if !@@has_colors || !CONFIG[:syntax_highlight]
+ syntax_table = @buffer.mode.syntax_table
+ return if syntax_table.empty?
+ if @buffer.bytesize < CONFIG[:highlight_buffer_size_limit]
+ base_pos = @buffer.point_min
+ s = @buffer.to_s
+ else
+ base_pos = @buffer.point
+ len = columns * (lines - 1) / 2 * 3
+ s = @buffer.substring(@buffer.point, @buffer.point + len).scrub("")
+ end
+ re_str = syntax_table.map { |name, re|
+ "(?<#{name}>#{re})"
+ }.join("|")
+ re = Regexp.new(re_str)
+ names = syntax_table.keys
+ s.scan(re) do
+ b = base_pos + $`.bytesize
+ e = b + $&.bytesize
+ if b < @buffer.point && @buffer.point < e
+ b = @buffer.point
+ end
+ name = names.find { |n| $~[n] }
+ attributes = Face[name]&.attributes
+ if attributes
+ @highlight_on[b] = attributes
+ @highlight_off[e] = attributes
+ end
+ end
+ end
+
def redisplay
return if @buffer.nil?
redisplay_mode_line
@buffer.save_point do |saved|
if current?
@@ -340,12 +416,14 @@
@buffer.point_to_mark(@point_mark)
end
framer
y = x = 0
@buffer.point_to_mark(@top_of_window)
+ highlight
@window.erase
@window.setpos(0, 0)
+ @window.attrset(0)
if current? && @buffer.visible_mark &&
@buffer.point_after_mark?(@buffer.visible_mark)
@window.attron(Curses::A_REVERSE)
end
while !@buffer.end_of_buffer?
@@ -366,10 +444,16 @@
@window.attroff(Curses::A_REVERSE)
elsif @buffer.point_before_mark?(point)
@window.attron(Curses::A_REVERSE)
end
end
+ if attrs = @highlight_off[@buffer.point]
+ @window.attroff(attrs)
+ end
+ if attrs = @highlight_on[@buffer.point]
+ @window.attron(attrs)
+ end
c = @buffer.char_after
if c == "\n"
@window.clrtoeol
break if cury == lines - 2 # lines include mode line
@window.setpos(cury + 1, 0)
@@ -476,22 +560,63 @@
@buffer.beginning_of_line
@top_of_window.location = 0
end
def split
- if lines < 6
- raise EditorError, "Window too small"
- end
old_lines = lines
new_lines = (old_lines / 2.0).ceil
+ if new_lines < CONFIG[:window_min_height]
+ raise EditorError, "Window too small"
+ end
resize(new_lines, columns)
new_window = Window.new(old_lines - new_lines, columns, y + new_lines, x)
new_window.buffer = buffer
i = @@windows.index(self)
@@windows.insert(i + 1, new_window)
end
+ def enlarge(n)
+ if n > 0
+ max_height = Window.lines -
+ CONFIG[:window_min_height] * (@@windows.size - 2) - 1
+ new_lines = [lines + n, max_height].min
+ needed_lines = new_lines - lines
+ resize(new_lines, columns)
+ i = @@windows.index(self)
+ indices = (i + 1).upto(@@windows.size - 2).to_a +
+ (i - 1).downto(0).to_a
+ indices.each do |j|
+ break if needed_lines == 0
+ window = @@windows[j]
+ extended_lines = [
+ window.lines - CONFIG[:window_min_height],
+ needed_lines
+ ].min
+ window.resize(window.lines - extended_lines, window.columns)
+ needed_lines -= extended_lines
+ end
+ y = 0
+ @@windows.each do |win|
+ win.move(y, win.x)
+ y += win.lines
+ end
+ elsif n < 0 && @@windows.size > 2
+ new_lines = [lines + n, CONFIG[:window_min_height]].max
+ diff = lines - new_lines
+ resize(new_lines, columns)
+ i = @@windows.index(self)
+ if i < @@windows.size - 2
+ window = @@windows[i + 1]
+ window.move(window.y - diff, window.x)
+ else
+ window = @@windows[i - 1]
+ move(self.y + diff, self.x)
+ end
+ window.resize(window.lines + diff, window.columns)
+ end
+ end
+
private
def initialize_window(num_lines, num_columns, y, x)
@window = Curses::Window.new(num_lines - 1, num_columns, y, x)
@mode_line = Curses::Window.new(1, num_columns, y + num_lines - 1, x)
@@ -520,11 +645,12 @@
end
def redisplay_mode_line
@mode_line.erase
@mode_line.setpos(0, 0)
- @mode_line.attron(Curses::A_REVERSE)
+ attrs = @@has_colors ? Face[:mode_line].attributes : Curses::A_REVERSE
+ @mode_line.attrset(attrs)
@mode_line.addstr("#{@buffer.name} ")
@mode_line.addstr("[+]") if @buffer.modified?
@mode_line.addstr("[RO]") if @buffer.read_only?
@mode_line.addstr("[#{@buffer.file_encoding.name}/")
@mode_line.addstr("#{@buffer.file_format}] ")
@@ -538,10 +664,10 @@
end
@mode_line.addstr(unicode_codepoint(c))
@mode_line.addstr(" #{line},#{column}")
@mode_line.addstr(" (#{@buffer.mode&.name || 'None'})")
@mode_line.addstr(" " * (columns - @mode_line.curx))
- @mode_line.attroff(Curses::A_REVERSE)
+ @mode_line.attrset(0)
@mode_line.noutrefresh
end
def unicode_codepoint(c)
if c.nil?