]> git.cworth.org Git - sup/blobdiff - lib/sup/textfield.rb
Merge branch 'master' into next
[sup] / lib / sup / textfield.rb
index bdd1228882e0bc552cd4b855961d1b6864516795..76803bf97c9a00bc394a6f9e59c4f26b6b318b9e 100644 (file)
@@ -1,22 +1,22 @@
-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 = []
 
@@ -27,22 +27,17 @@ class TextField
   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
@@ -50,7 +45,7 @@ class TextField
     @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
@@ -66,20 +61,21 @@ class TextField
     ## 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
@@ -94,6 +90,7 @@ class TextField
     end
 
     reset_completion_state
+    @value = nil
 
     d =
       case c
@@ -101,25 +98,33 @@ class TextField
         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
 
@@ -131,16 +136,25 @@ private
   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