diff options
-rw-r--r-- | doc/cha.1 | 58 | ||||
-rw-r--r-- | src/config/config.nim | 15 | ||||
-rw-r--r-- | src/main.nim | 306 | ||||
-rw-r--r-- | src/utils/twtstr.nim | 7 |
4 files changed, 209 insertions, 177 deletions
diff --git a/doc/cha.1 b/doc/cha.1 index fdda5fdc..ba5ffe47 100644 --- a/doc/cha.1 +++ b/doc/cha.1 @@ -35,11 +35,18 @@ provided, each letter is parsed as a separate short form. \fB\-\-abcd\fR.) .TP +\fB\-c, \-\-css\fR \fIstylesheet\fR +Temporarily modify the user stylesheet. If a user stylesheet is already +being used, the stylesheet given is appended to that. +.TP \fB\-d, \-\-dump\fR Start in headless mode, and sequentially print the opened files to stdout. This option is implicitly enabled if stdout is not a tty (e.g. when piping \fIcha\fR output). .TP +\fB\-h, \-\-help\fR +Print a short version of this page, then exit. +.TP \fB\-o, \-\-opt\fR \fIconfig\fR Override configuration options. This accepts the configuration format is described in \fBcha-config\fR(5), in other words the passed string must be @@ -50,14 +57,23 @@ parameters, unrecognized bare keywords are converted to strings. So this works: \fB--opt\fR abcd.option-name=\fIoption-value\fR. However, symbols must still be quoted.) .TP -\fB\-c, \-\-css\fR \fIstylesheet\fR -Temporarily modify the user stylesheet. If a user stylesheet is already -being used, the stylesheet given is appended to that. +\fB\-r, \-\-run\fR \fIscript\fR/\fIfile\fR +Execute the string provided as a JS script, or execute the supplied JS +file. If the file ends in .mjs, it is executed as an ES module. +.br +(To execute an inline script as a module, the following hack can be used: +.br +\fIcha \fB-r \fR'await new Promise(x => setTimeout(x, 1000)); +console.log("hello from ESM!"); //.mjs' +.br +In other words, we add a comment \fI//.mjs\fR to the end of the script.) .TP -\fB\-T, \-\-type\fR \fIcontent-type\fR -Override the content type of all input files. Useful when the content type -cannot be guessed from the file extension, or when reading a non-plaintext -file from stdin. +\fB\-v, \-\-version\fR +Print information about the browser's version, then exit. +.TP +\fB\-C, \-\-config\fR \fIfile\fR +Override the default configuration search path. Both absolute and relative +paths are allowed. .TP \fB\-I, \-\-input-charset\fR \fIcharset\fR Override the character set of all input files. Useful when Chawan is @@ -65,34 +81,22 @@ incorrectly recognizing the input character set. (Note: if this happens often, consider changing the default input charset recognition list \fIencoding.document-charset\fR in the configuration.) .TP +\fB\-M, \-\-monochrome\fR +Override the output character set. This is a shortcut for +\fB\-o display.color\-mode=\fImonochrome\fR. +.TP \fB\-O, \-\-output-charset\fR \fIcharset\fR Override the output character set. This is a shortcut for \fB\-o encoding.display\-charset=\fIcharset\fR. .TP -\fB\-M, \-\-monochrome\fR -Override the output character set. This is a shortcut for -\fB\-o display.color\-mode=\fImonochrome\fR. +\fB\-T, \-\-type\fR \fIcontent-type\fR +Override the content type of all input files. Useful when the content type +cannot be guessed from the file extension, or when reading a non-plaintext +file from stdin. .TP \fB\-V, \-\-visual\fR Start in visual mode: the page specified in \fIstart.visual-home\fR is opened. .TP -\fB\-r, \-\-run\fR \fIscript\fR/\fIfile\fR -Execute the string provided as a JS script, or execute the supplied JS -file. If the file ends in .mjs, it is executed as an ES module. -.br -(To execute an inline script as a module, the following hack can be used: -.br -\fIcha \fB-r \fR'await new Promise(x => setTimeout(x, 1000)); -console.log("hello from ESM!"); //.mjs' -.br -In other words, we add a comment \fI//.mjs\fR to the end of the script.) -.TP -\fB\-h, \-\-help\fR -Print a short version of this page, then exit. -.TP -\fB\-v, \-\-version\fR -Print information about the browser's version, then exit. -.TP \fB\-\-\fP Interpret all following arguments as files. (e.g. if you have a file named \fI\-o\fR, open it as \fIcha \fB--\fR \fI-o\fR. diff --git a/src/config/config.nim b/src/config/config.nim index 3d2769d4..99f9d9da 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -625,8 +625,8 @@ proc staticReadConfig(): ConfigObj = const defaultConfig = staticReadConfig() -proc readConfig(config: Config, dir: string) = - let fs = newFileStream(dir / "config.toml") +proc readConfig(config: Config, dir, name: string) = + let fs = openFileExpand(dir, name) if fs != nil: config.parseConfig(dir, fs) @@ -636,12 +636,15 @@ proc getNormalAction*(config: Config, s: string): string = proc getLinedAction*(config: Config, s: string): string = return config.line.getOrDefault(s) -proc readConfig*(): Config = +proc readConfig*(pathOverride: Option[string]): Config = result = Config() result[] = defaultConfig - when defined(debug): - result.readConfig(getCurrentDir() / "res") - result.readConfig(getConfigDir() / "chawan") + if pathOverride.isNone: + when defined(debug): + result.readConfig(getCurrentDir() / "res", "config.toml") + result.readConfig(getConfigDir() / "chawan", "config.toml") + else: + result.readConfig(getCurrentDir(), pathOverride.get) proc addConfigModule*(ctx: JSContext) = ctx.registerType(ActionMap) diff --git a/src/main.nim b/src/main.nim index 86066c28..47e00959 100644 --- a/src/main.nim +++ b/src/main.nim @@ -18,182 +18,200 @@ when defined(profile): import config/config import io/serversocket import local/client -import types/opt import utils/twtstr import chakasu/charset -let conf = readConfig() -set_cjk_ambiguous(conf.display.double_width_ambiguous) -let params = commandLineParams() +proc main() = + let params = commandLineParams() -proc version(long: static bool = false): string = - result = "Chawan browser v0.1 " - when defined(debug): - result &= "(debug)" - else: - result &= "(release)" + proc version(long: static bool = false): string = + result = "Chawan browser v0.1 " + when defined(debug): + result &= "(debug)" + else: + result &= "(release)" -proc help(i: int) = - let s = version() & """ + proc help(i: int) = + let s = version() & """ Usage: cha [options] [URL(s) or file(s)...] Options: -- Interpret all following arguments as URLs - -d, --dump Print page to stdout -c, --css <stylesheet> Pass stylesheet (e.g. -c 'a{color: blue}') + -d, --dump Print page to stdout + -h, --help Print this usage message -o, --opt <config> Pass config options (e.g. -o 'page.q="quit()"') - -T, --type <type> Specify content mime type + -r, --run <script/file> Run passed script or file + -v, --version Print version information + -C, --config <file> Override config path -I, --input-charset <enc> Specify document charset - -O, --display-charset <enc> Specify display charset -M, --monochrome Set color-mode to 'monochrome' - -V, --visual Visual startup mode - -r, --run <script/file> Run passed script or file - -h, --help Print this usage message - -v, --version Print version information""" - if i == 0: - stdout.write(s & '\n') - else: - stderr.write(s & '\n') - quit(i) - -var i = 0 -var ctype = none(string) -var cs = CHARSET_UNKNOWN -var pages: seq[string] -var dump = false -var visual = false -var escape_all = false - -while i < params.len: - let param = params[i] - - if escape_all: # after -- - pages.add(param) - inc i - continue + -O, --display-charset <enc> Specify display charset + -T, --type <type> Specify content mime type + -V, --visual Visual startup mode""" - proc getnext(): string = - inc i - if i < params.len: - return params[i] - help(1) + if i == 0: + stdout.write(s & '\n') + else: + stderr.write(s & '\n') + quit(i) + + var ctype = none(string) + var cs = CHARSET_UNKNOWN + var pages: seq[string] + var dump = false + var visual = false + var escape_all = false + var opts: seq[string] + var stylesheet = "" + var configPath = none(string) + + var i = 0 + while i < params.len: + let param = params[i] + + if escape_all: # after -- + pages.add(param) + inc i + continue - proc pversion() = - echo version(true) - quit(0) + proc getnext(): string = + inc i + if i < params.len: + return params[i] + help(1) - proc pmonochrome() = - conf.display.colormode.ok(MONOCHROME) + proc pconfig() = + configPath = some(getnext()) - proc pvisual() = - visual = true + proc pversion() = + echo version(true) + quit(0) - proc ptype() = - ctype = some(getnext()) + proc pmonochrome() = + opts.add("display.color-mode = monochrome") - proc pgetCharset(): Charset = - let s = getnext() - let cs = getCharset(s) - if cs == CHARSET_UNKNOWN: - stderr.write("Unknown charset " & s & "\n") - quit(1) - return cs + proc pvisual() = + visual = true - proc pinput_charset() = - cs = pgetCharset() + proc ptype() = + ctype = some(getnext()) - proc poutput_charset() = - conf.encoding.display_charset.ok(pgetCharset()) + proc pgetCharset(): Charset = + let s = getnext() + let cs = getCharset(s) + if cs == CHARSET_UNKNOWN: + stderr.write("Unknown charset " & s & "\n") + quit(1) + return cs - proc pdump() = - dump = true + proc pinput_charset() = + cs = pgetCharset() - proc pcss() = - conf.css.stylesheet &= getnext() + proc poutput_charset() = + opts.add("encoding.display-charset = '" & $pgetCharset() & "'") - proc popt() = - conf.parseConfig(getCurrentDir(), getnext(), laxnames = true) + proc pdump() = + dump = true - proc phelp() = - help(0) + proc pcss() = + stylesheet &= getnext() - proc prun() = - conf.start.startup_script = getnext() - conf.start.headless = true - dump = true + proc popt() = + opts.add(getnext()) - if param.len == 0: - inc i - continue + proc phelp() = + help(0) - const NeedsNextParam = {'T', 'I', 'O', 'c', 'o', 'r'} + proc prun() = + let script = dqEscape(getnext()) + opts.add("start.startup-script = \"\"\"" & script & "\"\"\"") + opts.add("start.headless = true") + dump = true - if param[0] == '-': - if param.len == 1: - # If param == "-", i.e. it is a single dash, then ignore it. - # (Some programs use single-dash to read from stdin, but we do that - # automatically when stdin is not a tty. So ignoring it entirely - # is probably for the best.) + if param.len == 0: inc i continue - if param[1] != '-': - for j in 1 ..< param.len: - if j != param.high and param[j] in NeedsNextParam: - # expecting next parameter, but not the last char... - help(1) - case param[j] - of 'v': pversion() - of 'M': pmonochrome() - of 'V': pvisual() - of 'T': ptype() - of 'I': pinput_charset() - of 'O': poutput_charset() - of 'd': pdump() - of 'c': pcss() - of 'o': popt() - of 'h': phelp() - of 'r': prun() + + const NeedsNextParam = {'C', 'I', 'O', 'T', 'c', 'o', 'r'} + + if param[0] == '-': + if param.len == 1: + # If param == "-", i.e. it is a single dash, then ignore it. + # (Some programs use single-dash to read from stdin, but we do that + # automatically when stdin is not a tty. So ignoring it entirely + # is probably for the best.) + inc i + continue + if param[1] != '-': + for j in 1 ..< param.len: + if j != param.high and param[j] in NeedsNextParam: + # expecting next parameter, but not the last char... + help(1) + case param[j] + of 'C': pconfig() + of 'I': pinput_charset() + of 'M': pmonochrome() + of 'O': poutput_charset() + of 'T': ptype() + of 'V': pvisual() + of 'c': pcss() + of 'd': pdump() + of 'h': phelp() + of 'o': popt() + of 'r': prun() + of 'v': pversion() + else: help(1) + else: + case param + of "--config": pconfig() + of "--input-charset": pinput_charset() + of "--monochrome": pmonochrome() + of "--output-charset": poutput_charset() + of "--type": ptype() + of "--visual": pvisual() + of "--css": pcss() + of "--dump": pdump() + of "--help": phelp() + of "--opt": popt() + of "--run": prun() + of "--version": pversion() + of "--": escape_all = true else: help(1) else: - case param - of "--version": pversion() - of "--monochrome": pmonochrome() - of "--visual": pvisual() - of "--type": ptype() - of "--input-charset": pinput_charset() - of "--output-charset": poutput_charset() - of "--dump": pdump() - of "--css": pcss() - of "--opt": popt() - of "--help": phelp() - of "--run": prun() - of "--": escape_all = true - else: help(1) - else: - pages.add(param) - inc i - -if pages.len == 0 and stdin.isatty(): - if visual: - pages.add(conf.start.visual_home) - else: - let http = getEnv("HTTP_HOME") - if http != "": pages.add(http) + pages.add(param) + inc i + + let config = readConfig(configPath) + for opt in opts: + config.parseConfig(getCurrentDir(), opt, laxnames = true) + config.css.stylesheet &= stylesheet + + set_cjk_ambiguous(config.display.double_width_ambiguous) + + if pages.len == 0 and stdin.isatty(): + if visual: + pages.add(config.start.visual_home) else: - let www = getEnv("WWW_HOME") - if www != "": pages.add(www) - -if pages.len == 0 and not conf.start.headless: - if stdin.isatty: - help(1) - -forks.loadForkServerConfig(conf) -SocketDirectory = conf.external.tmpdir - -let c = newClient(conf, forks, getpid()) -try: - c.launchClient(pages, ctype, cs, dump) -except CatchableError: - c.flushConsole() - raise + let http = getEnv("HTTP_HOME") + if http != "": pages.add(http) + else: + let www = getEnv("WWW_HOME") + if www != "": pages.add(www) + + if pages.len == 0 and not config.start.headless: + if stdin.isatty: + help(1) + + forks.loadForkServerConfig(config) + SocketDirectory = config.external.tmpdir + + let c = newClient(config, forks, getpid()) + try: + c.launchClient(pages, ctype, cs, dump) + except CatchableError: + c.flushConsole() + raise + +main() diff --git a/src/utils/twtstr.nim b/src/utils/twtstr.nim index f8557a85..327fae81 100644 --- a/src/utils/twtstr.nim +++ b/src/utils/twtstr.nim @@ -563,6 +563,13 @@ func htmlEscape*(s: string): string = res &= c return res +func dqEscape*(s: string): string = + result = newStringOfCap(s.len) + for c in s: + if c == '"': + result &= '\\' + result &= c + #basically std join but with char func join*(ss: openarray[string], sep: char): string = if ss.len == 0: |