about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buffer/buffer.nim53
-rw-r--r--src/buffer/container.nim34
-rw-r--r--src/display/client.nim17
-rw-r--r--src/display/pager.nim12
4 files changed, 73 insertions, 43 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim
index 8bfd3f6e..f20804c7 100644
--- a/src/buffer/buffer.nim
+++ b/src/buffer/buffer.nim
@@ -51,6 +51,10 @@ type
     GET_SOURCE, GET_LINES, UPDATE_HOVER, PASS_FD, CONNECT, GOTO_ANCHOR, CANCEL,
     GET_TITLE
 
+  HoverType* = enum
+    HOVER_TITLE = "TITLE"
+    HOVER_LINK = "URL"
+
   BufferMatch* = object
     success*: bool
     x*: int
@@ -88,7 +92,7 @@ type
     timeouts: Table[int, (proc())]
     tasks: array[BufferCommand, int] #TODO this should have arguments
     savetask: bool
-    hovertext: string
+    hovertext: array[HoverType, string]
 
   # async, but worse
   EmptyPromise = ref object of RootObj
@@ -280,15 +284,6 @@ func getTitleAttr(node: StyledNode): string =
         return element.attr("title")
   #TODO pseudo-elements
 
-func getLink(node: StyledNode): HTMLAnchorElement =
-  if node == nil:
-    return nil
-  if node.t == STYLED_ELEMENT and node.node != nil and Element(node.node).tagType == TAG_A:
-    return HTMLAnchorElement(node.node)
-  if node.node != nil:
-    return HTMLAnchorElement(node.node.findAncestor({TAG_A}))
-  #TODO ::before links?
-
 const ClickableElements = {
   TAG_A, TAG_INPUT, TAG_OPTION, TAG_BUTTON, TAG_TEXTAREA
 }
@@ -302,6 +297,22 @@ func getClickable(styledNode: StyledNode): Element =
       return element
   styledNode.node.findAncestor(ClickableElements)
 
+func getClickHover(styledNode: StyledNode): string =
+  let clickable = styledNode.getClickable()
+  if clickable != nil:
+    case clickable.tagType
+    of TAG_A:
+      return HTMLAnchorElement(clickable).href
+    of TAG_INPUT:
+      return "<input>"
+    of TAG_OPTION:
+      return "<option>"
+    of TAG_BUTTON:
+      return "<button>"
+    of TAG_TEXTAREA:
+      return "<textarea>"
+    else: discard
+
 func getCursorClickable(buffer: Buffer, cursorx, cursory: int): Element =
   let i = buffer.lines[cursory].findFormatN(cursorx) - 1
   if i >= 0:
@@ -489,7 +500,8 @@ proc windowChange*(buffer: Buffer, attrs: WindowAttributes) {.proxy.} =
   buffer.height = buffer.attrs.height - 1
 
 type UpdateHoverResult* = object
-  hover*: Option[string]
+  link*: Option[string]
+  title*: Option[string]
   repaint*: bool
 
 proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.proxy.} =
@@ -508,19 +520,14 @@ proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.pr
           elem.hover = true
           result.repaint = true
 
-    var upd = false
     let title = thisnode.getTitleAttr()
-    if title != "":
-      upd = true
-      buffer.hovertext = title
-    elif (let link = thisnode.getLink(); link != nil):
-      upd = true
-      buffer.hovertext = link.href
-    else:
-      upd = buffer.hovertext != ""
-      buffer.hovertext = ""
-    if upd:
-      result.hover = some(buffer.hovertext)
+    if buffer.hovertext[HOVER_TITLE] != title:
+      result.title = some(title)
+      buffer.hovertext[HOVER_TITLE] = title
+    let click = thisnode.getClickHover()
+    if buffer.hovertext[HOVER_LINK] != click:
+      result.link = some(click)
+      buffer.hovertext[HOVER_LINK] = click
 
     for styledNode in prevnode.branch:
       if styledNode.t == STYLED_ELEMENT and styledNode.node != nil:
diff --git a/src/buffer/container.nim b/src/buffer/container.nim
index 80044b60..66ef2780 100644
--- a/src/buffer/container.nim
+++ b/src/buffer/container.nim
@@ -72,7 +72,8 @@ type
     height*: int
     contenttype*: Option[string]
     title*: string
-    hovertext*: string
+    hovertext*: array[HoverType, string]
+    lastpeek: HoverType
     source*: BufferSource
     pos: CursorPosition
     bpos: seq[CursorPosition]
@@ -257,6 +258,11 @@ func findHighlights*(container: Container, y: int): seq[Highlight] =
     if y in hl:
       result.add(hl)
 
+func getHoverText*(container: Container): string =
+  for t in HoverType:
+    if container.hovertext[t] != "":
+      return container.hovertext[t]
+
 proc triggerEvent(container: Container, event: ContainerEvent) =
   container.events.addLast(event)
 
@@ -291,8 +297,11 @@ proc redraw*(container: Container) {.jsfunc.} =
 
 proc sendCursorPosition(container: Container) =
   container.iface.updateHover(container.cursorx, container.cursory).then(proc(res: UpdateHoverResult) =
-    if res.hover.isSome:
-      container.hovertext = res.hover.get
+    if res.link.isSome:
+      container.hovertext[HOVER_LINK] = res.link.get
+    if res.title.isSome:
+      container.hovertext[HOVER_TITLE] = res.title.get
+    if res.link.isSome or res.title.isSome:
       container.triggerEvent(STATUS)
     if res.repaint:
       container.needslines = true)
@@ -754,9 +763,24 @@ proc windowChange*(container: Container, attrs: WindowAttributes) =
 proc peek*(container: Container) {.jsfunc.} =
   container.alert($container.source.location)
 
+proc clearHover*(container: Container) =
+  container.lastpeek = low(HoverType)
+
 proc peekCursor*(container: Container) {.jsfunc.} =
-  if container.hovertext != "":
-    container.alert(container.hovertext)
+  var p = container.lastpeek
+  while true:
+    if container.hovertext[p] != "":
+      container.alert($p & ": " & container.hovertext[p])
+      break
+    if p < high(HoverType):
+      inc p
+    else:
+      p = low(HoverType)
+    if p == container.lastpeek: break
+  if container.lastpeek < high(HoverType):
+    inc container.lastpeek
+  else:
+    container.lastpeek = low(HoverType)
 
 proc handleCommand(container: Container) =
   var packetid, len: int
diff --git a/src/display/client.nim b/src/display/client.nim
index 5162d4aa..cf27eac4 100644
--- a/src/display/client.nim
+++ b/src/display/client.nim
@@ -140,6 +140,11 @@ proc feedNext(client: Client) {.jsfunc.} =
 proc alert(client: Client, msg: string) {.jsfunc.} =
   client.pager.alert(msg)
 
+proc handlePagerEvents(client: Client) =
+  let container = client.pager.container
+  if container != nil and not client.pager.handleEvents(container):
+    client.quit(1)
+
 proc input(client: Client) =
   restoreStdin(client.console.tty.getFileHandle())
   while true:
@@ -169,6 +174,7 @@ proc input(client: Client) =
       let action = getNormalAction(client.config, client.s)
       client.evalJSFree(action, "<command>")
       if not client.feedNext:
+        client.handlePagerEvents()
         client.pager.refreshStatusMsg()
     if not client.feedNext:
       client.s = ""
@@ -282,10 +288,7 @@ proc inputLoop(client: Client) =
       if Read in event.events:
         if event.fd == client.console.tty.getFileHandle():
           client.input()
-          let container = client.pager.container
-          if container != nil and not client.pager.handleEvents(container):
-            client.quit(1)
-          stdout.flushFile()
+          client.handlePagerEvents()
         else:
           let container = client.fdmap[event.fd]
           if not client.pager.handleEvent(container):
@@ -310,7 +313,7 @@ proc inputLoop(client: Client) =
     if client.pager.scommand != "":
       client.command(client.pager.scommand)
       client.pager.scommand = ""
-      client.pager.refreshStatusMsg()
+      client.handlePagerEvents()
     client.pager.draw()
     client.acceptBuffers()
 
@@ -334,10 +337,6 @@ proc dumpLoop(client: Client) =
           let timeout = client.timeouts[id]
           timeout.handler()
           client.clearTimeout(id)
-    if client.pager.scommand != "":
-      client.command(client.pager.scommand)
-      client.pager.scommand = ""
-      client.pager.refreshStatusMsg()
     client.acceptBuffers()
 
 proc headlessLoop(client: Client) =
diff --git a/src/display/pager.nim b/src/display/pager.nim
index f61304aa..53388052 100644
--- a/src/display/pager.nim
+++ b/src/display/pager.nim
@@ -250,7 +250,7 @@ proc refreshDisplay(pager: Pager, container = pager.container) =
 proc clearStatusMessage(pager: Pager) =
   pager.statusgrid = newFixedGrid(pager.statusgrid.width)
 
-proc writeStatusMessage(pager: Pager, str: string, format: Format = Format()) =
+proc writeStatusMessage(pager: Pager, str: string, format: Format = newFormat()) =
   pager.clearStatusMessage()
   var i = 0
   for r in str.runes:
@@ -275,11 +275,13 @@ proc refreshStatusMsg*(pager: Pager) =
     pager.writeStatusMessage(pager.alerts[0])
     pager.alerts.delete(0)
   else:
+    container.clearHover()
     var msg = $(container.cursory + 1) & "/" & $container.numLines & " (" &
               $container.atPercentOf() & "%) " & "<" & container.getTitle() & ">"
-    if container.hovertext.len > 0:
-      msg &= " " & container.hovertext
-    var format: Format
+    let h = container.getHoverText()
+    if h != "":
+      msg &= " " & h
+    var format = newFormat()
     format.reverse = true
     pager.writeStatusMessage(msg, format)
 
@@ -717,7 +719,6 @@ proc handleEvent0(pager: Pager, container: Container, event: ContainerEvent): bo
       pager.gotoURL(newRequest(container.retry.pop()), ctype = container.contenttype)
     else:
       pager.alert("Can't load " & $container.source.location & " (error code " & $container.code & ")")
-      pager.refreshStatusMsg()
     if pager.container == nil:
       return false
   of SUCCESS:
@@ -785,7 +786,6 @@ proc handleEvent0(pager: Pager, container: Container, event: ContainerEvent): bo
   of ALERT:
     if pager.container == container:
       pager.alert(event.msg)
-      pager.refreshStatusMsg()
   of NO_EVENT: discard
   return true