about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display/pager.nim18
-rw-r--r--src/io/lineedit.nim108
-rw-r--r--src/io/term.nim83
-rw-r--r--src/utils/eprint.nim13
4 files changed, 125 insertions, 97 deletions
diff --git a/src/display/pager.nim b/src/display/pager.nim
index a7f4a1d6..119b5002 100644
--- a/src/display/pager.nim
+++ b/src/display/pager.nim
@@ -123,18 +123,18 @@ proc clearLineEdit(pager: Pager) =
 func attrs(pager: Pager): WindowAttributes = pager.term.attrs
 
 proc searchForward(pager: Pager) {.jsfunc.} =
-  pager.setLineEdit(readLine("/", pager.attrs.width, config = pager.config, tty = pager.tty), SEARCH_F)
+  pager.setLineEdit(readLine("/", pager.attrs.width, term = pager.term), SEARCH_F)
 
 proc searchBackward(pager: Pager) {.jsfunc.} =
-  pager.setLineEdit(readLine("?", pager.attrs.width, config = pager.config, tty = pager.tty), SEARCH_B)
+  pager.setLineEdit(readLine("?", pager.attrs.width, term = pager.term), SEARCH_B)
 
 proc isearchForward(pager: Pager) {.jsfunc.} =
   pager.container.pushCursorPos()
-  pager.setLineEdit(readLine("/", pager.attrs.width, config = pager.config, tty = pager.tty), ISEARCH_F)
+  pager.setLineEdit(readLine("/", pager.attrs.width, term = pager.term), ISEARCH_F)
 
 proc isearchBackward(pager: Pager) {.jsfunc.} =
   pager.container.pushCursorPos()
-  pager.setLineEdit(readLine("?", pager.attrs.width, config = pager.config, tty = pager.tty), ISEARCH_B)
+  pager.setLineEdit(readLine("?", pager.attrs.width, term = pager.term), ISEARCH_B)
 
 proc newPager*(config: Config, attrs: WindowAttributes, dispatcher: Dispatcher): Pager =
   let pager = Pager(
@@ -481,7 +481,7 @@ proc readPipe*(pager: Pager, ctype: Option[string], fd: FileHandle) =
   pager.addContainer(container)
 
 proc command(pager: Pager) {.jsfunc.} =
-  pager.setLineEdit(readLine("COMMAND: ", pager.attrs.width, config = pager.config, tty = pager.tty), COMMAND)
+  pager.setLineEdit(readLine("COMMAND: ", pager.attrs.width, term = pager.term), COMMAND)
 
 proc commandMode(pager: Pager) {.jsfunc.} =
   pager.commandmode = true
@@ -529,7 +529,7 @@ proc updateReadLine*(pager: Pager) =
       of LOCATION: pager.loadURL(s)
       of USERNAME:
         pager.username = s
-        pager.setLineEdit(readLine("Password: ", pager.attrs.width, hide = true, config = pager.config, tty = pager.tty), PASSWORD)
+        pager.setLineEdit(readLine("Password: ", pager.attrs.width, hide = true, term = pager.term), PASSWORD)
       of PASSWORD:
         let url = newURL(pager.container.source.location)
         url.username = pager.username
@@ -568,7 +568,7 @@ proc updateReadLine*(pager: Pager) =
 # Open a URL prompt and visit the specified URL.
 proc changeLocation(pager: Pager) {.jsfunc.} =
   var url = pager.container.source.location.serialize()
-  pager.setLineEdit(readLine("URL: ", pager.attrs.width, current = url, config = pager.config, tty = pager.tty), LOCATION)
+  pager.setLineEdit(readLine("URL: ", pager.attrs.width, current = url, term = pager.term), LOCATION)
 
 # Reload the page in a new buffer, then kill the previous buffer.
 proc reload(pager: Pager) {.jsfunc.} =
@@ -578,7 +578,7 @@ proc click(pager: Pager) {.jsfunc.} =
   pager.container.click()
 
 proc authorize*(pager: Pager) =
-  pager.setLineEdit(readLine("Username: ", pager.attrs.width, config = pager.config, tty = pager.tty), USERNAME)
+  pager.setLineEdit(readLine("Username: ", pager.attrs.width, term = pager.term), USERNAME)
 
 proc handleEvent*(pager: Pager, container: Container): bool =
   var event: ContainerEvent
@@ -627,7 +627,7 @@ proc handleEvent*(pager: Pager, container: Container): bool =
       pager.redraw = true
   of READ_LINE:
     if container == pager.container:
-      pager.setLineEdit(readLine(event.prompt, pager.attrs.width, current = event.value, hide = event.password, config = pager.config, tty = pager.tty), BUFFER)
+      pager.setLineEdit(readLine(event.prompt, pager.attrs.width, current = event.value, hide = event.password, term = pager.term), BUFFER)
   of OPEN:
     pager.gotoURL(event.request, some(container.source.location))
   of INVALID_COMMAND: discard
diff --git a/src/io/lineedit.nim b/src/io/lineedit.nim
index a12604cb..6673676d 100644
--- a/src/io/lineedit.nim
+++ b/src/io/lineedit.nim
@@ -1,4 +1,3 @@
-import terminal
 import unicode
 import strutils
 import sequtils
@@ -6,8 +5,9 @@ import sugar
 
 import bindings/quickjs
 import buffer/cell
-import config/config
+import io/term
 import js/javascript
+import types/color
 import utils/twtstr
 
 type
@@ -28,8 +28,35 @@ type
     displen: int
     disallowed: set[char]
     hide: bool
-    config: Config #TODO get rid of this
-    tty: File
+    term: Terminal
+
+proc printesc(edit: LineEdit, rs: seq[Rune]) =
+  var s = ""
+  var format = newFormat()
+  var cformat = newFormat()
+  cformat.fgcolor = ColorsANSIFg[4] # blue
+  var dformat = newFormat() # reset
+  for r in rs:
+    if r.isControlChar():
+      s &= edit.term.processFormat(format, cformat)
+    else:
+      s &= edit.term.processFormat(format, dformat)
+    s &= r
+  edit.term.write(s)
+
+proc printesc(edit: LineEdit, s: string) =
+  var s = ""
+  var format = newFormat()
+  var cformat = newFormat()
+  cformat.fgcolor = ColorsANSIFg[4] # blue
+  var dformat = newFormat() # reset
+  for r in s.runes:
+    if r.isControlChar():
+      s &= edit.term.processFormat(format, cformat)
+    else:
+      s &= edit.term.processFormat(format, dformat)
+    s &= r
+  edit.term.write(s)
 
 func lwidth(r: Rune): int =
   if r.isControlChar():
@@ -66,25 +93,20 @@ template kill0(edit: LineEdit) =
   edit.kill0(w)
 
 proc backward0(state: LineEdit, i: int) =
-  if i > 0:
-    if i == 1:
-      print('\b')
-    else:
-      cursorBackward(i)
+  state.term.cursorBackward(i)
 
 proc forward0(state: LineEdit, i: int) =
-  if i > 0:
-    cursorForward(i)
+  state.term.cursorForward(i)
 
-proc begin0(state: LineEdit) =
-  print('\r')
-  state.forward0(state.minlen)
+proc begin0(edit: LineEdit) =
+  edit.term.cursorBegin()
+  edit.forward0(edit.minlen)
 
 proc space(edit: LineEdit, i: int) =
-  print(' '.repeat(i))
+  edit.term.write(' '.repeat(i))
 
 proc generateOutput*(edit: LineEdit): FixedGrid =
-  result = newFixedGrid(edit.maxlen)
+  result = newFixedGrid(edit.promptw + edit.maxlen)
   let os = edit.news.substr(edit.shift, edit.shift + edit.displen)
   var x = 0
   for r in edit.prompt.runes():
@@ -94,12 +116,12 @@ proc generateOutput*(edit: LineEdit): FixedGrid =
     for r in os:
       result[x].str = "*"
       x += r.lwidth()
-      if x > result.width: break
+      if x >= result.width: break
   else:
     for r in os:
       result[x].str &= $r
       x += r.lwidth()
-      if x > result.width: break
+      if x >= result.width: break
 
 proc getCursorX*(edit: LineEdit): int =
   return edit.promptw + edit.news.lwidth(edit.shift, edit.cursor)
@@ -114,9 +136,9 @@ proc redraw(state: LineEdit) =
   state.begin0()
   let os = state.news.substr(state.shift, state.shift + state.displen)
   if state.hide:
-    printesc('*'.repeat(os.lwidth()))
+    state.printesc('*'.repeat(os.lwidth()))
   else:
-    printesc($os)
+    state.printesc(os)
   state.space(max(state.maxlen - state.minlen - os.lwidth(), 0))
   state.begin0()
   state.forward0(state.news.lwidth(state.shift, state.cursor))
@@ -148,9 +170,9 @@ proc insertCharseq(state: LineEdit, cs: var seq[Rune], disallowed: set[char]) =
     state.news &= cs
     state.cursor += cs.len
     if state.hide:
-      printesc('*'.repeat(cs.lwidth()))
+      state.printesc('*'.repeat(cs.lwidth()))
     else:
-      printesc($cs)
+      state.printesc(cs)
   else:
     state.news.insert(cs, state.cursor)
     state.cursor += cs.len
@@ -290,32 +312,32 @@ proc `end`*(edit: LineEdit) {.jsfunc.} =
       edit.fullRedraw()
     edit.cursor = edit.news.len
 
-proc writePrompt*(lineedit: LineEdit) =
-  printesc(lineedit.prompt)
+proc writePrompt*(edit: LineEdit) =
+  edit.printesc(edit.prompt)
 
-proc writeStart*(lineedit: LineEdit) =
-  lineedit.writePrompt()
-  if lineedit.hide:
-    printesc('*'.repeat(lineedit.current.lwidth()))
+proc writeStart*(edit: LineEdit) =
+  edit.writePrompt()
+  if edit.hide:
+    edit.printesc('*'.repeat(edit.current.lwidth()))
   else:
-    printesc(lineedit.current)
+    edit.printesc(edit.current)
 
 proc readLine*(prompt: string, termwidth: int, current = "",
-               disallowed: set[char] = {}, hide = false, config: Config,
-               tty: File): LineEdit =
-  new(result)
-  result.prompt = prompt
-  result.promptw = prompt.lwidth()
-  result.current = current
-  result.news = current.toRunes()
-  result.cursor = result.news.len
-  result.minlen = prompt.lwidth()
-  result.maxlen = termwidth - prompt.len
+               disallowed: set[char] = {}, hide = false,
+               term: Terminal): LineEdit =
+  result = LineEdit(
+    prompt: prompt,
+    promptw: prompt.lwidth(),
+    current: current,
+    news: current.toRunes(),
+    minlen: prompt.lwidth(),
+    disallowed: disallowed,
+    hide: hide,
+    term: term
+  )
+  result.cursor = result.news.lwidth()
+  result.maxlen = termwidth - result.promptw
   result.displen = result.maxlen - 1
-  result.disallowed = disallowed
-  result.hide = hide
-  result.config = config
-  result.tty = tty
 
 proc addLineEditModule*(ctx: JSContext) =
   ctx.registerType(LineEdit)
diff --git a/src/io/term.nim b/src/io/term.nim
index 82cb19fd..7d3786e0 100644
--- a/src/io/term.nim
+++ b/src/io/term.nim
@@ -27,6 +27,8 @@ type
     ue # end underline mode
     se # end standout mode
     me # end all formatting modes
+    LE # cursor left %1 characters
+    RI # cursor right %1 characters
 
   Termcap = ref object
     bp: array[1024, uint8]
@@ -63,38 +65,35 @@ template CSI*(s: varargs[string, `$`]): string =
     r &= x
   r
 
-template DECSET(s: varargs[string, `$`]): string =
-  var r = "\e[?"
-  var first = true
-  for x in s:
-    if not first:
-      r &= ";"
-    first = false
-    r &= x
-  r & "h"
-
-template DECRST(s: varargs[string, `$`]): string =
-  var r = "\e[?"
-  var first = true
-  for x in s:
-    if not first:
-      r &= ";"
-    first = false
-    r &= x
-  r & "l"
-
-template SMCUP(): string = DECSET(1049)
-template RMCUP(): string = DECRST(1049)
+when not termcap_found:
+  template DECSET(s: varargs[string, `$`]): string =
+    var r = "\e[?"
+    var first = true
+    for x in s:
+      if not first:
+        r &= ";"
+      first = false
+      r &= x
+    r & "h"
+  template DECRST(s: varargs[string, `$`]): string =
+    var r = "\e[?"
+    var first = true
+    for x in s:
+      if not first:
+        r &= ";"
+      first = false
+      r &= x
+    r & "l"
+  template SMCUP(): string = DECSET(1049)
+  template RMCUP(): string = DECRST(1049)
+  template HVP(s: varargs[string, `$`]): string =
+    CSI(s) & "f"
+  template EL(s: varargs[string, `$`]): string =
+    CSI(s) & "K"
 
 template SGR*(s: varargs[string, `$`]): string =
   CSI(s) & "m"
 
-template HVP(s: varargs[string, `$`]): string =
-  CSI(s) & "f"
-
-template EL*(s: varargs[string, `$`]): string =
-  CSI(s) & "K"
-
 const ANSIColorMap = [
   ColorsRGB["black"],
   ColorsRGB["red"],
@@ -110,7 +109,7 @@ var goutfile: File
 proc putc(c: char): cint {.cdecl.} =
   goutfile.write(c)
 
-proc write(term: Terminal, s: string) =
+proc write*(term: Terminal, s: string) =
   when termcap_found:
     discard tputs(cstring(s), cint(s.len), putc)
   else:
@@ -137,10 +136,30 @@ proc resetFormat(term: Terminal): string =
   else:
     return SGR()
 
-#TODO get rid of this
+#TODO get rid of these
 proc setCursor*(term: Terminal, x, y: int) =
   term.write(term.cursorGoto(x, y))
 
+proc cursorBackward*(term: Terminal, i: int) =
+  if i > 0:
+    if i == 1:
+      term.write("\b")
+    else:
+      when termcap_found:
+        term.write($tgoto(term.ccap LE, cint(i), 0))
+      else:
+        term.outfile.cursorBackward(i)
+
+proc cursorForward*(term: Terminal, i: int) =
+  if i > 0:
+    when termcap_found:
+      term.write($tgoto(term.ccap RI, cint(i), 0))
+    else:
+      term.outfile.cursorForward(i)
+
+proc cursorBegin*(term: Terminal) =
+  term.write("\r")
+
 proc enableAltScreen(term: Terminal): string =
   when termcap_found:
     if term.hascap ti:
@@ -251,7 +270,7 @@ proc processFormat*(term: Terminal, format: var Format, cellf: Format): string =
       let rgb = color.rgbcolor
       result &= SGR(48, 2, rgb.r, rgb.g, rgb.b)
     elif color == defaultColor:
-      result &= SGR()
+      result &= term.resetFormat()
       format = newFormat()
     else:
       result &= SGR(color.color)
@@ -271,7 +290,7 @@ proc windowChange*(term: Terminal, attrs: WindowAttributes) =
 func generateFullOutput(term: Terminal, grid: FixedGrid): string =
   var format = newFormat()
   result &= term.cursorGoto(0, 0)
-  result &= SGR()
+  result &= term.resetFormat()
   for y in 0 ..< grid.height:
     for x in 0 ..< grid.width:
       let cell = grid[y * grid.width + x]
diff --git a/src/utils/eprint.nim b/src/utils/eprint.nim
index 6a76d250..c5936d2a 100644
--- a/src/utils/eprint.nim
+++ b/src/utils/eprint.nim
@@ -19,16 +19,3 @@ template eprint*(s: varargs[string, `$`]) = {.cast(noSideEffect), cast(tags: [])
         stderr.write(' ')
       stderr.write(x)
     stderr.write('\n')
-
-template print*(s: varargs[string, `$`]) =
-  for x in s:
-    stdout.write(x)
-
-template printesc*(s: string) =
-  for r in s.runes:
-    if r.isControlChar():
-      stdout.write(('^' & $($r)[0].getControlLetter())
-                   .ansiFgColor(fgBlue).ansiStyle(styleBright).ansiReset())
-    else:
-      stdout.write($r)
-