about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-03-18 16:32:40 +0100
committerbptato <nincsnevem662@gmail.com>2024-03-18 16:41:10 +0100
commit50ee9b03e320628b73d511c7d5ae217b07f00cce (patch)
treeaf1443a6dd310721dbf0a27d1f008a30b26f2cfa
parentc0af45b47a78bc4d3f07d84b2e04d61e9ced75ac (diff)
downloadchawan-50ee9b03e320628b73d511c7d5ae217b07f00cce.tar.gz
config: parse mime.types/mailcap/urimethodmap inside parseConfig
Better (and simpler) than storing them all over the place.

extra: change lmDownload text to match w3m
-rw-r--r--src/config/config.nim146
-rw-r--r--src/config/mimetypes.nim6
-rw-r--r--src/local/client.nim2
-rw-r--r--src/local/pager.nim25
-rw-r--r--src/utils/mimeguess.nim1
5 files changed, 76 insertions, 104 deletions
diff --git a/src/config/config.nim b/src/config/config.nim
index b019ec70..23762c02 100644
--- a/src/config/config.nim
+++ b/src/config/config.nim
@@ -19,7 +19,6 @@ import types/cookie
 import types/opt
 import types/urimethodmap
 import types/url
-import utils/mimeguess
 import utils/twtstr
 
 import chagashi/charset
@@ -73,10 +72,10 @@ type
   ExternalConfig = object
     tmpdir* {.jsgetset.}: ChaPathResolved
     editor* {.jsgetset.}: string
-    mailcap* {.jsgetset.}: seq[ChaPathResolved]
-    mime_types* {.jsgetset.}: seq[ChaPathResolved]
+    mailcap*: Mailcap
+    mime_types*: MimeTypes
     cgi_dir* {.jsgetset.}: seq[ChaPathResolved]
-    urimethodmap* {.jsgetset.}: seq[ChaPathResolved]
+    urimethodmap*: URIMethodMap
     download_dir* {.jsgetset.}: string
     w3m_cgi_compat* {.jsgetset.}: bool
 
@@ -280,85 +279,6 @@ proc readUserStylesheet(dir, file: string): string =
     result = s.readAll()
     s.close()
 
-# The overall configuration will be obtained through the virtual concatenation
-# of several individual configuration files known as mailcap files.
-proc getMailcap*(config: Config): tuple[mailcap: Mailcap, errs: seq[string]] =
-  let configDir = config.configdir
-  template uq(s: string): string =
-    ChaPath(s).unquote.get
-  let gopherPath = "${%CHA_LIBEXEC_DIR}/gopher2html -u \\$MAILCAP_URL".uq
-  let geminiPath = "${%CHA_LIBEXEC_DIR}/gmi2html".uq
-  let mdPath = "${%CHA_LIBEXEC_DIR}/md2html".uq
-  let ansiPath = "${%CHA_LIBEXEC_DIR}/ansi2html".uq
-  var mailcap: Mailcap = @[]
-  var errs: seq[string]
-  var found = false
-  for p in config.external.mailcap:
-    let f = openFileExpand(configDir, p)
-    if f != nil:
-      let res = parseMailcap(f)
-      if res.isSome:
-        mailcap.add(res.get)
-      else:
-        errs.add(res.error)
-      found = true
-  mailcap.add(MailcapEntry(
-      mt: "text",
-      subt: "gopher",
-      cmd: gopherPath,
-      flags: {HTMLOUTPUT}
-  ))
-  mailcap.add(MailcapEntry(
-    mt: "text",
-    subt: "gemini",
-    cmd: geminiPath,
-    flags: {HTMLOUTPUT}
-  ))
-  mailcap.add(MailcapEntry(
-    mt: "text",
-    subt: "markdown",
-    cmd: mdPath,
-    flags: {HTMLOUTPUT}
-  ))
-  mailcap.add(MailcapEntry(
-    mt: "text",
-    subt: "x-ansi",
-    cmd: ansiPath,
-    flags: {HTMLOUTPUT}
-  ))
-  return (mailcap, errs)
-
-# We try to source mime types declared in config.
-# If none of these files can be found, fall back to DefaultGuess.
-#TODO some error handling would be nice, to at least show a warning to
-# the user. Not sure how this could be done, though.
-proc getMimeTypes*(config: Config): MimeTypes =
-  if config.external.mime_types.len == 0:
-    return DefaultGuess
-  var mimeTypes: MimeTypes
-  let configDir = config.configdir
-  var found = false
-  for p in config.external.mime_types:
-    let f = openFileExpand(configDir, p)
-    if f != nil:
-      mimeTypes.parseMimeTypes(f)
-      found = true
-  if not found:
-    return DefaultGuess
-  return mimeTypes
-
-const DefaultURIMethodMap = parseURIMethodMap(staticRead"res/urimethodmap")
-
-proc getURIMethodMap*(config: Config): URIMethodMap =
-  let configDir = config.configdir
-  var urimethodmap: URIMethodMap
-  for p in config.external.urimethodmap:
-    let f = openFileExpand(configDir, p)
-    if f != nil:
-      urimethodmap.parseURIMethodMap(f.readAll())
-  urimethodmap.append(DefaultURIMethodMap)
-  return urimethodmap
-
 proc getForkServerConfig*(config: Config): ForkServerConfig =
   return ForkServerConfig(
     tmpdir: config.external.tmpdir,
@@ -416,6 +336,12 @@ proc parseConfigValue[T](ctx: var ConfigParser; x: var proc(x: T): JSResult[T];
   v: TomlValue; k: string)
 proc parseConfigValue(ctx: var ConfigParser; x: var ChaPathResolved;
   v: TomlValue; k: string)
+proc parseConfigValue(ctx: var ConfigParser; x: var MimeTypes; v: TomlValue;
+  k: string)
+proc parseConfigValue(ctx: var ConfigParser; x: var Mailcap; v: TomlValue;
+  k: string)
+proc parseConfigValue(ctx: var ConfigParser; x: var URIMethodMap; v: TomlValue;
+  k: string)
 
 proc typeCheck(v: TomlValue, vt: ValueType, k: string) =
   if v.vt != vt:
@@ -659,9 +585,61 @@ proc parseConfigValue(ctx: var ConfigParser; x: var ChaPathResolved;
     raise newException(ValueError, y.error)
   x = ChaPathResolved(y.get)
 
+proc parseConfigValue(ctx: var ConfigParser; x: var MimeTypes; v: TomlValue;
+    k: string) =
+  var paths: seq[ChaPathResolved]
+  ctx.parseConfigValue(paths, v, k)
+  x = default(MimeTypes)
+  for p in paths:
+    let f = openFileExpand(ctx.config.configdir, p)
+    if f != nil:
+      x.parseMimeTypes(f)
+
+proc parseConfigValue(ctx: var ConfigParser; x: var Mailcap; v: TomlValue;
+    k: string) =
+  var paths: seq[ChaPathResolved]
+  ctx.parseConfigValue(paths, v, k)
+  x = default(Mailcap)
+  for p in paths:
+    let f = openFileExpand(ctx.config.configdir, p)
+    if f != nil:
+      let res = parseMailcap(f)
+      if res.isSome:
+        x.add(res.get)
+      else:
+        ctx.warnings.add("Error reading mailcap: " & res.error)
+  template uq(s: string): string =
+    ChaPath(s).unquote.get
+  let defaultCmds = {
+    "gopher": "${%CHA_LIBEXEC_DIR}/gopher2html -u \\$MAILCAP_URL".uq,
+    "gemini": "${%CHA_LIBEXEC_DIR}/gmi2html".uq,
+    "markdown": "${%CHA_LIBEXEC_DIR}/md2html".uq,
+    "x-ansi":"${%CHA_LIBEXEC_DIR}/ansi2html".uq
+  }
+  for (subt, cmd) in defaultCmds:
+    x.add(MailcapEntry(
+      mt: "text",
+      subt: subt,
+      cmd: cmd,
+      flags: {HTMLOUTPUT}
+    ))
+
+const DefaultURIMethodMap = parseURIMethodMap(staticRead"res/urimethodmap")
+
+proc parseConfigValue(ctx: var ConfigParser; x: var URIMethodMap; v: TomlValue;
+    k: string) =
+  var paths: seq[ChaPathResolved]
+  ctx.parseConfigValue(paths, v, k)
+  x = default(URIMethodMap)
+  for p in paths:
+    let f = openFileExpand(ctx.config.configdir, p)
+    if f != nil:
+      x.parseURIMethodMap(f.readAll())
+  x.append(DefaultURIMethodMap)
+
 type ParseConfigResult* = object
   success*: bool
-  warnings*: seq[string] #TODO actually use warnings
+  warnings*: seq[string]
   errorMsg*: string
 
 proc parseConfig(config: Config; dir: string; stream: Stream; name = "<input>";
diff --git a/src/config/mimetypes.nim b/src/config/mimetypes.nim
index 542bc267..e8a0fd07 100644
--- a/src/config/mimetypes.nim
+++ b/src/config/mimetypes.nim
@@ -4,7 +4,11 @@ import std/tables
 import utils/twtstr
 
 # extension -> type
-type MimeTypes* = Table[string, string]
+type MimeTypes* = distinct Table[string, string]
+
+proc `[]`*(mimeTypes: MimeTypes; k: string): string {.borrow.}
+proc contains*(mimeTypes: MimeTypes; k: string): bool {.borrow.}
+proc hasKeyOrPut*(mimeTypes: var MimeTypes; k, v: string): bool {.borrow.}
 
 # Add mime types found in stream to mimeTypes.
 # No error handling for now.
diff --git a/src/local/client.nim b/src/local/client.nim
index b59e1ef4..8b16339f 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -890,7 +890,7 @@ proc newClient*(config: Config; forkserver: ForkServer; jsctx: JSContext):
   JS_SetModuleLoaderFunc(jsrt, normalizeModuleName, clientLoadJSModule, nil)
   let pager = newPager(config, forkserver, jsctx)
   let loader = forkserver.newFileLoader(LoaderConfig(
-    urimethodmap: config.getURIMethodMap(),
+    urimethodmap: config.external.urimethodmap,
     w3mCGICompat: config.external.w3m_cgi_compat,
     cgiDir: seq[string](config.external.cgi_dir),
     tmpdir: config.external.tmpdir
diff --git a/src/local/pager.nim b/src/local/pager.nim
index f5dbff4b..7c986eff 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -14,7 +14,6 @@ when defined(posix):
 import bindings/libregexp
 import config/config
 import config/mailcap
-import config/mimetypes
 import io/posixstream
 import io/promise
 import io/serialize
@@ -42,7 +41,6 @@ import types/color
 import types/cookie
 import types/opt
 import types/referrer
-import types/urimethodmap
 import types/url
 import types/winattrs
 import utils/strwidth
@@ -62,7 +60,7 @@ type
     lmISearchF = "/"
     lmISearchB = "?"
     lmGotoLine = "Goto line: "
-    lmDownload = "(Download) Save file to: "
+    lmDownload = "(Download)Save file to: "
 
   # fdin is the original fd; fdout may be the same, or different if mailcap
   # is used.
@@ -121,8 +119,6 @@ type
     linehist: array[LineMode, LineHistory]
     linemode: LineMode
     loader*: FileLoader
-    mailcap: Mailcap
-    mimeTypes: MimeTypes
     notnum*: bool # has a non-numeric character been input already?
     numload*: int # number of pages currently being loaded
     precnum*: int32 # current number prefix (when vi-numeric-prefix is true)
@@ -136,7 +132,6 @@ type
     statusgrid*: FixedGrid
     term*: Terminal
     unreg*: seq[Container]
-    urimethodmap: URIMethodMap
 
 jsDestructor(Pager)
 
@@ -277,18 +272,12 @@ proc quit*(pager: Pager, code = 0) =
   pager.dumpAlerts()
 
 proc newPager*(config: Config; forkserver: ForkServer; ctx: JSContext): Pager =
-  let (mailcap, errs) = config.getMailcap()
   let pager = Pager(
     config: config,
     forkserver: forkserver,
-    mailcap: mailcap,
-    mimeTypes: config.getMimeTypes(),
     proxy: config.getProxy(),
-    term: newTerminal(stdout, config),
-    urimethodmap: config.getURIMethodMap()
+    term: newTerminal(stdout, config)
   )
-  for err in errs:
-    pager.alert("Error reading mailcap: " & err)
   return pager
 
 proc genClientKey(pager: Pager): ClientKey =
@@ -1271,7 +1260,8 @@ type CheckMailcapResult = object
 
 # Pipe output of an x-ansioutput mailcap command to the text/x-ansi handler.
 proc ansiDecode(pager: Pager; url: URL; ishtml: var bool; fdin: cint): cint =
-  let entry = pager.mailcap.getMailcapEntry("text/x-ansi", "", url)
+  let entry = pager.config.external.mailcap.getMailcapEntry("text/x-ansi", "",
+    url)
   var canpipe = true
   let cmd = unquoteCommand(entry.cmd, "text/x-ansi", "", url, canpipe)
   if not canpipe:
@@ -1483,7 +1473,8 @@ proc checkMailcap(pager: Pager; container: Container; stream: SocketStream;
     return CheckMailcapResult(connect: true, fdout: stream.fd, found: true)
   #TODO callback for outpath or something
   let url = container.url
-  let entry = pager.mailcap.getMailcapEntry(contentType, "", url)
+  let entry = pager.config.external.mailcap.getMailcapEntry(contentType, "",
+    url)
   if entry == nil:
     return CheckMailcapResult(connect: true, fdout: stream.fd, found: false)
   let ext = url.pathname.afterLast('.')
@@ -1555,7 +1546,7 @@ proc fail(pager: Pager; container: Container; errorMessage: string) =
 proc redirect(pager: Pager; container: Container; response: Response;
     request: Request) =
   # still need to apply response, or we lose cookie jars.
-  container.applyResponse(response, pager.mimeTypes)
+  container.applyResponse(response, pager.config.external.mime_types)
   if container.redirectDepth < pager.config.network.max_redirect:
     if container.url.scheme == request.url.scheme or
         container.url.scheme == "cgi-bin" or
@@ -1574,7 +1565,7 @@ proc redirect(pager: Pager; container: Container; response: Response;
 
 proc connected(pager: Pager; container: Container; response: Response) =
   let istream = response.body
-  container.applyResponse(response, pager.mimeTypes)
+  container.applyResponse(response, pager.config.external.mime_types)
   if response.status == 401: # unauthorized
     pager.setLineEdit(lmUsername)
     pager.lineData = LineDataAuth(url: container.url)
diff --git a/src/utils/mimeguess.nim b/src/utils/mimeguess.nim
index f13eaf89..5bbabcc1 100644
--- a/src/utils/mimeguess.nim
+++ b/src/utils/mimeguess.nim
@@ -1,6 +1,5 @@
 import std/algorithm
 import std/streams
-import std/tables
 
 import config/mimetypes