diff options
author | bptato <nincsnevem662@gmail.com> | 2024-03-16 18:24:42 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-03-16 18:25:24 +0100 |
commit | a83c0be8abb07e736297dcc6d6304bfbb243eb99 (patch) | |
tree | f118e60b4da3ce625155d1bd1394effe983ba4b4 /src/local | |
parent | 1d2b576e408059f500e97e52e8930d2cb7c38551 (diff) | |
download | chawan-a83c0be8abb07e736297dcc6d6304bfbb243eb99.tar.gz |
pager, loader: add "Save file to" functionality
As simple as it could be; no download panel yet. Also, remove the xdg-open default mailcap entry; it's better to just save by default.
Diffstat (limited to 'src/local')
-rw-r--r-- | src/local/pager.nim | 85 |
1 files changed, 74 insertions, 11 deletions
diff --git a/src/local/pager.nim b/src/local/pager.nim index 5dbb8ae0..80a001e4 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -53,8 +53,9 @@ import chagashi/charset type LineMode* = enum - NO_LINEMODE, LOCATION, USERNAME, PASSWORD, COMMAND, BUFFER, SEARCH_F, - SEARCH_B, ISEARCH_F, ISEARCH_B, GOTO_LINE + LOCATION, USERNAME, PASSWORD, COMMAND, BUFFER, SEARCH_F, SEARCH_B, + ISEARCH_F, ISEARCH_B, GOTO_LINE, + DOWNLOAD = "(Download) Save file to" # fdin is the original fd; fdout may be the same, or different if mailcap # is used. @@ -79,6 +80,12 @@ type outputId: int status: uint16 + LineData = ref object of RootObj + + LineDataDownload = ref object of LineData + outputId: int + stream: Stream + Pager* = ref object alertState: PagerAlertState alerts: seq[string] @@ -98,6 +105,7 @@ type inputBuffer*: string # currently uninterpreted characters iregex: Result[Regex, string] isearchpromise: EmptyPromise + lineData: LineData lineedit*: Option[LineEdit] linehist: array[LineMode, LineHistory] linemode: LineMode @@ -206,13 +214,13 @@ proc searchPrev(pager: Pager, n = 1) {.jsfunc.} = pager.container.cursorNextMatch(pager.regex.get, wrap, true, n) pager.container.markPos() -proc getLineHist(pager: Pager, mode: LineMode): LineHistory = +proc getLineHist(pager: Pager; mode: LineMode): LineHistory = if pager.linehist[mode] == nil: pager.linehist[mode] = newLineHistory() return pager.linehist[mode] -proc setLineEdit(pager: Pager, prompt: string, mode: LineMode, - current = "", hide = false) = +proc setLineEdit(pager: Pager; prompt: string; mode: LineMode; current = ""; + hide = false) = let hist = pager.getLineHist(mode) if pager.term.isatty() and pager.config.input.use_mouse: pager.term.disableMouse() @@ -220,6 +228,9 @@ proc setLineEdit(pager: Pager, prompt: string, mode: LineMode, pager.lineedit = some(edit) pager.linemode = mode +proc setLineEdit(pager: Pager; mode: LineMode; current = "") = + pager.setLineEdit($mode, mode, current) + proc clearLineEdit(pager: Pager) = pager.lineedit = none(LineEdit) if pager.term.isatty() and pager.config.input.use_mouse: @@ -1118,6 +1129,23 @@ proc updateReadLineISearch(pager: Pager, linemode: LineMode) = pager.isearchpromise = nil ) +proc saveTo(pager: Pager; data: LineDataDownload; path: string) = + if pager.loader.redirectToFile(data.outputId, path): + pager.alert("Saving file to " & path) + pager.loader.resume(@[data.outputId]) + data.stream.close() + pager.lineData = nil + else: + pager.ask("Failed to save to path " & path & ". Retry?").then( + proc(x: bool) = + if x: + pager.alert("Failed to save to path " & path) + pager.setLineEdit(DOWNLOAD, path) + else: + data.stream.close() + pager.lineData = nil + ) + proc updateReadLine*(pager: Pager) = let lineedit = pager.lineedit.get if pager.linemode in {ISEARCH_F, ISEARCH_B}: @@ -1154,7 +1182,18 @@ proc updateReadLine*(pager: Pager) = pager.searchNext() of GOTO_LINE: pager.container.gotoLine(lineedit.news) - else: discard + of DOWNLOAD: + let data = LineDataDownload(pager.lineData) + if fileExists(lineedit.news): + pager.ask("Override file " & lineedit.news & "?").then( + proc(x: bool) = + if x: + pager.saveTo(data, lineedit.news) + else: + pager.setLineEdit(DOWNLOAD, lineedit.news) + ) + pager.saveTo(data, lineedit.news) + of ISEARCH_F, ISEARCH_B: discard of CANCEL: case pager.linemode of USERNAME: pager.discardBuffer() @@ -1163,7 +1202,11 @@ proc updateReadLine*(pager: Pager) = pager.discardBuffer() of BUFFER: pager.container.readCanceled() of COMMAND: pager.commandMode = false + of DOWNLOAD: + let data = LineDataDownload(pager.lineData) + data.stream.close() else: discard + pager.lineData = nil if lineedit.state in {LineEditState.CANCEL, LineEditState.FINISH}: if pager.lineedit.get == lineedit: pager.clearLineEdit() @@ -1242,6 +1285,7 @@ type CheckMailcapResult = object ostreamOutputId: int connect: bool ishtml: bool + found: bool # 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 = @@ -1443,17 +1487,22 @@ proc checkMailcap(pager: Pager; container: Container; stream: SocketStream; if shortContentType == "text/html": # We support text/html natively, so it would make little sense to execute # mailcap filters for it. - return CheckMailcapResult(connect: true, fdout: stream.fd, ishtml: true) + return CheckMailcapResult( + connect: true, + fdout: stream.fd, + ishtml: true, + found: true + ) if shortContentType == "text/plain": # text/plain could potentially be useful. Unfortunately, many mailcaps # include a text/plain entry with less by default, so it's probably better # to ignore this. - return CheckMailcapResult(connect: true, fdout: stream.fd) + 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) if entry == nil: - return CheckMailcapResult(connect: true, fdout: stream.fd) + return CheckMailcapResult(connect: true, fdout: stream.fd, found: false) let tmpdir = pager.tmpdir let ext = url.pathname.afterLast('.') let tempfile = getTempFile(tmpdir, ext) @@ -1499,10 +1548,11 @@ proc checkMailcap(pager: Pager; container: Container; stream: SocketStream; connect: true, fdout: response.body.fd, ostreamOutputId: response.outputId, - ishtml: ishtml + ishtml: ishtml, + found: true ) delEnv("MAILCAP_URL") - return CheckMailcapResult(connect: false, fdout: -1) + return CheckMailcapResult(connect: false, fdout: -1, found: true) proc redirectTo(pager: Pager; container: Container; request: Request) = pager.gotoURL(request, some(container.url), replace = container, @@ -1554,6 +1604,19 @@ proc connected(pager: Pager; container: Container; response: Response) = container.contentType.get & ";charset=" & $container.charset let mailcapRes = pager.checkMailcap(container, istream, response.outputId, realContentType) + if not mailcapRes.found: + pager.setLineEdit(DOWNLOAD, + pager.config.external.download_dir & + container.url.pathname.afterLast('/')) + pager.lineData = LineDataDownload( + outputId: response.outputId, + stream: istream + ) + pager.deleteContainer(container) + pager.redraw = true + pager.refreshStatusMsg() + dec pager.numload + return if mailcapRes.connect: container.ishtml = mailcapRes.ishtml # buffer now actually exists; create a process for it |