-require 'curses'
-
module Redwood
## a fully-functional text field supporting completions, expansions,
## history--everything!
+##
+## writing this fucking sucked. if you thought ncurses was some 1970s
+## before-people-knew-how-to-program bullshit, wait till you see
+## ncurses forms.
##
-## completion is done emacs-style, and mostly depends on outside
-## support, as we merely signal the existence of a new set of
-## completions to show (#new_completions?) or that the current list
-## of completions should be rolled if they're too large to fill the
-## screen (#roll_completions?).
+## completion comments: completion is done emacs-style, and mostly
+## depends on outside support, as we merely signal the existence of a
+## new set of completions to show (#new_completions?) or that the
+## current list of completions should be rolled if they're too large
+## to fill the screen (#roll_completions?).
##
## in sup, completion support is implemented through BufferManager#ask
## and CompletionMode.
class TextField
- def initialize window, y, x, width
- @w, @x, @y = window, x, y
- @width = width
+ def initialize
@i = nil
@history = []
bool_reader :new_completions, :roll_completions
attr_reader :completions
- ## when the user presses enter, we store the value in @value and
- ## clean up all the ncurses cruft. before @value is set, we can
- ## get the current value from ncurses.
- def value; @field ? get_cur_value : @value end
+ def value; @value || get_cursed_value end
- def activate question, default=nil, &block
+ def activate window, y, x, width, question, default=nil, &block
+ @w, @y, @x, @width = window, y, x, width
@question = question
- @value = nil
@completion_block = block
- @field = Ncurses::Form.new_field 1, @width - question.length,
- @y, @x + question.length, 0, 0
+ @field = Ncurses::Form.new_field 1, @width - question.length, @y, @x + question.length, 256, 0
@form = Ncurses::Form.new_form [@field]
-
- @history[@i = @history.size] = default || ""
+ @value = default || ''
Ncurses::Form.post_form @form
- set_cur_value @history[@i]
+ set_cursed_value @value
end
def position_cursor
@w.mvaddstr @y, 0, @question
Ncurses.curs_set 1
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
- Ncurses::Form.form_driver @form, Ncurses::Form::REQ_NEXT_CHAR if @history[@i] =~ / $/ # fucking RETARDED!!!!
+ Ncurses::Form.form_driver @form, Ncurses::Form::REQ_NEXT_CHAR if @value && @value =~ / $/ # fucking RETARDED
end
def deactivate
## short-circuit exit paths
case c
when Ncurses::KEY_ENTER # submit!
- @value = @history[@i] = get_cur_value
+ @value = get_cursed_value
+ @history.push @value unless @value =~ /^\s*$/
return false
when Ncurses::KEY_CANCEL # cancel
- @history.delete_at @i
- @i = @history.empty? ? nil : (@i - 1) % @history.size
@value = nil
return false
when Ncurses::KEY_TAB # completion
- break unless @completion_block
+ return true unless @completion_block
if @completions.empty?
- v = get_cur_value
+ v = get_cursed_value
c = @completion_block.call v
if c.size > 0
- set_cur_value c.map { |full, short| full }.shared_prefix
+ @value = c.map { |full, short| full }.shared_prefix(true)
+ set_cursed_value @value
+ position_cursor
end
if c.size > 1
@completions = c
end
reset_completion_state
+ @value = nil
d =
case c
Ncurses::Form::REQ_PREV_CHAR
when Ncurses::KEY_RIGHT
Ncurses::Form::REQ_NEXT_CHAR
- when Ncurses::KEY_BACKSPACE
+ when Ncurses::KEY_DC
+ Ncurses::Form::REQ_DEL_CHAR
+ when Ncurses::KEY_BACKSPACE, 127 # 127 is also a backspace keysym
Ncurses::Form::REQ_DEL_PREV
- when ?\001
+ when 1 #ctrl-a
Ncurses::Form::REQ_BEG_FIELD
- when ?\005
+ when 5 #ctrl-e
Ncurses::Form::REQ_END_FIELD
- when Ncurses::KEY_UP
- @history[@i] = @field.field_buffer 0
- @i = (@i - 1) % @history.size
- set_cur_value @history[@i]
- when Ncurses::KEY_DOWN
- @history[@i] = @field.field_buffer 0
- @i = (@i + 1) % @history.size
- set_cur_value @history[@i]
+ when 11 # ctrl-k
+ Ncurses::Form::REQ_CLR_EOF
+ when Ncurses::KEY_UP, Ncurses::KEY_DOWN
+ unless @history.empty?
+ value = get_cursed_value
+ @i ||= @history.size
+ #debug "history before #{@history.inspect}"
+ @history[@i] = value #unless value =~ /^\s*$/
+ @i = (@i + (c == Ncurses::KEY_UP ? -1 : 1)) % @history.size
+ @value = @history[@i]
+ #debug "history after #{@history.inspect}"
+ set_cursed_value @value
+ Ncurses::Form::REQ_END_FIELD
+ end
else
c
end
- Ncurses::Form.form_driver @form, d
+ Ncurses::Form.form_driver @form, d if d
true
end
end
## ncurses inanity wrapper
- def get_cur_value
+ ##
+ ## DO NOT READ THIS CODE. YOU WILL GO MAD.
+ def get_cursed_value
+ return nil unless @field
+
+ x = Ncurses.curx
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_VALIDATION
- @field.field_buffer(0).gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ")
+ v = @field.field_buffer(0).gsub(/^\s+|\s+$/, "")
+
+ ## cursor <= end of text
+ if x - @question.length - v.length <= 0
+ v
+ else # trailing spaces
+ v + (" " * (x - @question.length - v.length))
+ end
end
-
- ## ncurses inanity wrapper
- def set_cur_value v
+
+ def set_cursed_value v
@field.set_field_buffer 0, v
- Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
end
-
end
end