Module: Curses::WindowExtensions

Included in:
Window
Defined in:
lib/rodo/curses_util.rb

Instance Method Summary collapse

Instance Method Details

#addstr_with_cursor(line, cursor_x) ⇒ Object


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rodo/curses_util.rb', line 72

def addstr_with_cursor(line, cursor_x)
  line = line + " "

  Curses.debug "Before Cursor: '#{line[...cursor_x]}'"
  Curses.debug "Cursor_x: '#{cursor_x}'"

  cursor_x = 0 if cursor_x < 0
  cursor_x = line.size - 1 if cursor_x >= line.size

  addstr line[...cursor_x] if cursor_x > 0
  attron(Curses::A_REVERSE)
  addstr line[cursor_x]
  attroff(Curses::A_REVERSE)
  addstr(line[(cursor_x+1)..]) if cursor_x < line.size
  addstr("\n")
end

#box(*args) ⇒ Object

Override box() to call box(0, 0)


42
43
44
45
46
47
48
# File 'lib/rodo/curses_util.rb', line 42

def box(*args)
  if args.size == 0
    super(0, 0)
  else
    super(*args)
  end
end

#caption(string) ⇒ Object

Add the given string to the top left borner of a box window


65
66
67
68
69
70
# File 'lib/rodo/curses_util.rb', line 65

def caption(string)
  p = getyx
  setpos(0,1)
  addstr(string)
  setpos(*p)
end

#get_char2Object

Just like get_char, but will read x1b[<csi> return it as a hash { csi: … }, everything else is just returned as-is


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/rodo/curses_util.rb', line 138

def get_char2
  c = get_char
  case c
  when "\e" # ESC
    d = get_char
    case d
    when '['
      return { csi: get_csi }
    else
      Curses.unget_char(d)
      return "\e"
      # Curses.abort("Unhandled command sequence")
      # raise "¯\_(ツ)_/¯"
    end
  else
    return c
  end
end

#get_char3Object

Just like get_char2, but will read csi: “200~” as bracketed paste and return it as a hash { paste: <text> }, everything else is just returned as from get_char2


160
161
162
163
164
165
166
167
168
# File 'lib/rodo/curses_util.rb', line 160

def get_char3
  c = get_char2
  case c
  in csi: "200~" # Bracketed paste started
    return { paste: get_paste_text }
  else
    return c
  end
end

#get_csiObject

Reads a Control Sequence Introducer (CSI) from ‘get_char`

Requires that ANSI Control Sequence “x1b[” has already been consumed.

Assumes that there are no errors in the CSI.

For CSI, or “Control Sequence Introducer” commands, the ESC [ is followed by 1.) any number (including none) of “parameter bytes” in the range

0x30–0x3F (ASCII 0–9:;<=>?), then by

2.) any number of “intermediate bytes” in the range

0x20–0x2F (ASCII space and !"#$%&'()*+,-./), then finally by

3.) a single “final byte” in the range

0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).

From: handwiki.org/wiki/ANSI_escape_code


122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rodo/curses_util.rb', line 122

def get_csi

  result = "".dup
  loop do
    c = get_char
    result += c
    if c.ord >= 0x40 && c.ord <= 0x7E
      return result
    end
  end

end

#get_paste_textObject

Will read until the end of a bracketed paste marker “x1b[201~” Requires that the “x1b[200~” start marker has already been processed. The returned text does NOT include the end marker “200~”


92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rodo/curses_util.rb', line 92

def get_paste_text
  pasted = ""
  loop do
    d = get_char2
    case d
    in csi: "201~" # Bracketed paste ended
      break
    else
      pasted += d
    end
  end
  return pasted
end

#gets(start_string) ⇒ Object

Will take care of reading a string from the user, given the start_string


171
172
173
174
175
176
177
178
179
180
181
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/rodo/curses_util.rb', line 171

def gets(start_string)

  line = start_string
  cursor_x = line.length
  start_pos = getyx

  loop do

    clear
    setpos(*start_pos)
    addstr_with_cursor(line, cursor_x)

    yield line

    char = get_char
    case char

    when CTRLC, CTRLC.chr, ESC, ESC.chr
      return :close

    when "\u0001" # CTRL+A
      cursor_x = 0

    when "\u0005" # CTRL+E
      cursor_x = line.length

    when Curses::KEY_LEFT
      cursor_x -= 1 if cursor_x > 0

    when Curses::KEY_RIGHT
      cursor_x += 1 if cursor_x < line.length - 1

    when Curses::KEY_DC, "\u0004" # DEL, CTRL+D
      if cursor_x < line.size
        line.slice!(cursor_x)
      end

    when Curses::KEY_BACKSPACE
      if cursor_x > 0
        line.slice!(cursor_x - 1)
        cursor_x -= 1
      end

    when ENTER, ENTER.chr
      return line

    when /[[:print:]]/

      line.insert(cursor_x, char)
      cursor_x += 1

    else
      Curses.debug "Char not handled: " + Curses::char_info(char)
    end

  end

end

#getyxObject

Return the current coordinates of the cursor [y,x]


60
61
62
# File 'lib/rodo/curses_util.rb', line 60

def getyx
  return [cury(), curx()]
end

#inset(n = 1) ⇒ Object

Create a subwindow inside this window which is padded by the given number n (lines and characters)


37
38
39
# File 'lib/rodo/curses_util.rb', line 37

def inset(n=1)
  subwin(maxy - 2 * n, maxx - 2 * n, begy + n, begx + n)
end

#puts(string) ⇒ Object

Add the given string to this window and put the cursor on the next line


51
52
53
54
55
56
57
# File 'lib/rodo/curses_util.rb', line 51

def puts(string)
  if maxx - curx == string.length
    addstr(string)
  else
    addstr(string + "\n")
  end
end