about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/html/dom.nim8
-rw-r--r--src/local/container.nim14
-rw-r--r--src/local/pager.nim3
-rw-r--r--src/server/buffer.nim46
-rw-r--r--src/types/urimethodmap.nim2
5 files changed, 63 insertions, 10 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 163e4a66..39083db2 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -3334,8 +3334,8 @@ proc insertNode(parent, node, before: Node) =
     insertionSteps(node)
 
 # WARNING ditto
-proc insert*(parent, node, before: Node, suppressObservers = false) =
-  let nodes = if node of DocumentFragment:
+proc insert*(parent, node, before: Node; suppressObservers = false) =
+  var nodes = if node of DocumentFragment:
     node.childList
   else:
     @[node]
@@ -3381,7 +3381,7 @@ proc removeChild(parent, node: Node): DOMResult[Node] {.jsfunc.} =
 # doesn't match that
 # Note: the standard returns child if not err. We don't, it's just a
 # pointless copy.
-proc replace(parent, child, node: Node): Err[DOMException] =
+proc replace*(parent, child, node: Node): Err[DOMException] =
   ?checkParentValidity(parent)
   if node.isHostIncludingInclusiveAncestor(parent):
     return errDOMException("Parent must be an ancestor",
@@ -4036,7 +4036,7 @@ proc toBlob(ctx: JSContext, this: HTMLCanvasElement, callback: JSValue,
 
 import html/chadombuilder
 # https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm
-proc fragmentParsingAlgorithm(element: Element, s: string): DocumentFragment =
+proc fragmentParsingAlgorithm*(element: Element; s: string): DocumentFragment =
   #TODO xml
   let newChildren = parseHTMLFragment(element, s)
   let fragment = element.document.newDocumentFragment()
diff --git a/src/local/container.nim b/src/local/container.nim
index e722ccfd..d706b77c 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -149,6 +149,7 @@ type
     tailOnLoad*: bool
     cacheFile* {.jsget.}: string
     userRequested*: bool
+    mainConfig*: Config
 
 jsDestructor(Highlight)
 jsDestructor(Container)
@@ -157,7 +158,7 @@ proc newContainer*(config: BufferConfig; loaderConfig: LoaderClientConfig;
     url: URL; request: Request; attrs: WindowAttributes; title: string;
     redirectDepth: int; canReinterpret: bool; contentType: Option[string];
     charsetStack: seq[Charset]; cacheId: int; cacheFile: string;
-    userRequested: bool): Container =
+    userRequested: bool; mainConfig: Config): Container =
   return Container(
     url: url,
     request: request,
@@ -176,7 +177,8 @@ proc newContainer*(config: BufferConfig; loaderConfig: LoaderClientConfig;
     cacheId: cacheId,
     cacheFile: cacheFile,
     process: -1,
-    userRequested: userRequested
+    userRequested: userRequested,
+    mainConfig: mainConfig
   )
 
 func location(container: Container): URL {.jsfget.} =
@@ -1344,6 +1346,14 @@ proc getSelectionText(container: Container, hl: Highlight = nil):
     return s
   )
 
+proc markURL(container: Container) {.jsfunc.} =
+  var schemes: seq[string] = @[]
+  for key in container.mainConfig.external.urimethodmap.map.keys:
+    schemes.add(key.until(':'))
+  container.iface.markURL(schemes).then(proc() =
+    container.needslines = true
+  )
+
 proc setLoadInfo(container: Container, msg: string) =
   container.loadinfo = msg
   container.triggerEvent(cetSetLoadInfo)
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 627a7b08..e7d771c0 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -533,7 +533,8 @@ proc newContainer(pager: Pager; bufferConfig: BufferConfig;
     charsetStack,
     cacheId,
     cacheFile,
-    userRequested
+    userRequested,
+    pager.config
   )
   pager.connectingContainers.add(ConnectingContainerItem(
     state: ccsBeforeResult,
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 7bdd46d0..43b08b18 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -1,4 +1,4 @@
-from std/strutils import split, toUpperAscii
+from std/strutils import split, toUpperAscii, find
 
 import std/macros
 import std/nativesockets
@@ -11,6 +11,7 @@ import std/streams
 import std/tables
 import std/unicode
 
+import bindings/libregexp
 import bindings/quickjs
 import config/config
 import css/cascade
@@ -64,7 +65,7 @@ type
     bcReadSuccess, bcReadCanceled, bcClick, bcFindNextLink, bcFindPrevLink,
     bcFindNthLink, bcFindRevNthLink, bcFindNextMatch, bcFindPrevMatch,
     bcGetLines, bcUpdateHover, bcGotoAnchor, bcCancel, bcGetTitle, bcSelect,
-    bcClone, bcFindPrevParagraph, bcFindNextParagraph
+    bcClone, bcFindPrevParagraph, bcFindNextParagraph, bcMarkURL
 
   BufferState = enum
     bsLoadingPage, bsLoadingResources, bsLoaded
@@ -1649,6 +1650,47 @@ proc getLines*(buffer: Buffer, w: Slice[int]): GetLinesResult {.proxy.} =
   result.numLines = buffer.lines.len
   result.bgcolor = buffer.bgcolor
 
+proc markURL*(buffer: Buffer; schemes: seq[string]) {.proxy.} =
+  if buffer.document == nil or buffer.document.body == nil:
+    return
+  var buf = "("
+  for i, scheme in schemes:
+    if i > 0:
+      buf &= '|'
+    buf &= scheme
+  buf &= r"):(//[\w%:.-]+)?[\w/@%:.~-]*\??[\w%:~.=&]*#?[\w:~.=-]*[\w/~=-]"
+  let regex = compileRegex(buf, {LRE_FLAG_GLOBAL}).get
+  # Dummy element for the fragment parsing algorithm. We can't just use parent
+  # there, because e.g. plaintext would not parse the text correctly.
+  let html = buffer.document.newHTMLElement(TAG_DIV)
+  var stack = @[buffer.document.body]
+  while stack.len > 0:
+    let element = stack.pop()
+    for i in countdown(element.childList.high, 0):
+      let node = element.childList[i]
+      if node of Text:
+        let text = Text(node)
+        var res = regex.exec(text.data)
+        if res.success:
+          var data = text.data
+          var offset = 0
+          for cap in res.captures.mitems:
+            if cap.i != 0:
+              continue
+            cap.s += offset
+            cap.e += offset
+            let s = data[cap.s..<cap.e]
+            let news = "<a href=\"" & s & "\">" & s.htmlEscape() & "</a>"
+            data[cap.s..<cap.e] = news
+            offset += news.len - (cap.e - cap.s)
+          let replacement = html.fragmentParsingAlgorithm(data)
+          discard element.replace(text, replacement)
+      elif node of HTMLElement:
+        let element = HTMLElement(node)
+        if element.tagType notin {TAG_HEAD, TAG_SCRIPT, TAG_STYLE, TAG_A}:
+          stack.add(element)
+  buffer.do_reshape()
+
 macro bufferDispatcher(funs: static ProxyMap, buffer: Buffer,
     cmd: BufferCommand, packetid: int) =
   let switch = newNimNode(nnkCaseStmt)
diff --git a/src/types/urimethodmap.nim b/src/types/urimethodmap.nim
index 464c9b69..41e887c6 100644
--- a/src/types/urimethodmap.nim
+++ b/src/types/urimethodmap.nim
@@ -8,7 +8,7 @@ import types/url
 import utils/twtstr
 
 type URIMethodMap* = object
-  map: Table[string, string]
+  map*: Table[string, string]
 
 func rewriteURL(pattern, surl: string): string =
   result = ""