From 4ecfe688a016232656b383f82da4d6e2ba75a328 Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Fri, 8 Aug 2025 09:47:52 +0530 Subject: Generate docs --- Makefile | 7 +- TODO.org | 7 +- doc/index.html | 1228 +++++++++++++++++++++++++++++++++++ doc/ldoc.css | 304 +++++++++ flake.nix | 1 + init.lua | 6 +- lua/null-browser/api.lua | 221 +++---- lua/null-browser/extras/tabline.lua | 3 + lua/null-browser/utils.lua | 37 +- 9 files changed, 1670 insertions(+), 144 deletions(-) create mode 100644 doc/index.html create mode 100644 doc/ldoc.css diff --git a/Makefile b/Makefile index 23f8f82..1272245 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean build build-release dev-setup build-dev install build-source test run check fmt +.PHONY: clean build build-release dev-setup build-dev install build-source test run check fmt docs all: build-dev @@ -45,6 +45,11 @@ fmt: check: fmt clang-tidy --config-file=.clang-tidy ./src/**/*.{hpp,cpp} +docs: + ldoc -p null-browser -t "Null browser api" \ + --merge --ignore --lls \ + ./lua/null-browser/ + # appimage: # nix bundle --bundler github:ralismark/nix-appimage diff --git a/TODO.org b/TODO.org index 16dc417..032946b 100644 --- a/TODO.org +++ b/TODO.org @@ -12,11 +12,14 @@ - [X] Show number of tabs in statusline - [X] On finder stop, exit find mode - [X] Callback for result of run_js -- [ ] Generate docs for api +- [X] Generate docs for api +- [ ] Any hint action/generic (currently only url open) +- [ ] Document events and event opts - [ ] Embed docs in app (`null:/docs`) - [ ] Update all api to use opts table pattern - [ ] web.decorations.*.set_size() - [ ] web.keymap.configure_mode(modename, { passthrough = false }) +- [ ] Vertical tabline ui - [ ] Fullscreen - [ ] Zoom in/out/reset - [ ] Remove unwanted "async"-ness in lua calls @@ -31,6 +34,8 @@ - [ ] Managing focus in decorations? ** Next +- [ ] View focus event (between decorations/views) +- [ ] Element focus (input focus) - [ ] User scripts (greasemonkey?) - [ ] User stylesheets (per site and global?) - [ ] Log stdout, errors and results from lua somewhere diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..f357409 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,1228 @@ + + + + + Null browser api + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module web

+

+

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
schedule (fn)Schedule a function to be called on next tick (qt+libuv event loop)
web.keymap.set (mode, key, action)Add a keymap
web.keymap.set_mode (mode)Set the current keymap mode
web.keymap.get_mode ()Get the current keymap mode
web.view.close (view_id)Close view
web.view.create (url)Create a new view with a url
web.view.current ()Get current view id
web.view.list ()Get a list of views in the current window
web.view.select (view_id)Select a view in current window
web.view.set_url (url, view_id)Set url of a given view
web.view.set_html (html, opts)Set html inside the page for a given view
web.view.run_js (js, opts)Run js in a view
web.view.reload (opts)Relaod a given view
web.view.expose (name, action, opts)Expose a lua function inside a view (Only works with decorations)
web.view.open_devtools (view_id)Open devtools window for the view
web.view.current_index ()Get current view index
web.event.add_listener (events, opts)Listen to events from the browser
set (key, value)Set configuration options
get (key)Get configuration value
web.history.back (count, view_id)Go back in history for given view
web.history.forward (count, view_id)Go forward in history for given view
web.search.set_text (text, view_id)Search text inside a view
web.search.reset (view_id)Reset searched text in a view (Same as web.search.set_text(''))
web.search.get_text ()Get the last searched text
web.search.next (view_id)Highlight next search term for the last searched text
web.search.previous (view_id)Highlight previous search term for the last searched text
web.view.scroll (deltax, deltay, view_id)TODO: Document
web.view.scroll_to_top (view_id)TODO: Document
web.view.scroll_to_bottom (view_id)TODO: Document
web.utils.string_trim (str)Trim whitespace from start and end of a string
web.utils.table_merge (tbl)Merge multiple tables
web.utils.table_keys (tbl)Get keys of a table
web.utils.equals (a, b)Check if 2 values are deeply equal
+

Tables

+ + + + + +
WebOptsMaps to values defined in ./src/Configuration.hpp
+

Fields

+ + + + + + + + + + + + + + + + + +
_G.__internalsInternal api (unstable)
optsAPI for configuring browser options
uvluv api (https://github.com/luvit/luv/blob/master/docs.md)
inspectReturns human-readable string representation of Lua tables (https://github.com/kikito/inspect.lua)
+ +
+
+ + +

Functions

+ +
+
+ + schedule (fn) +
+
+ Schedule a function to be called on next tick (qt+libuv event loop) + + +

Parameters:

+
    +
  • fn + fun + ():nil Function to call +
  • +
+ + + + + +
+
+ + web.keymap.set (mode, key, action) +
+
+ Add a keymap + + +

Parameters:

+
    +
  • mode + string Keymap mode ("i", "n", ...) +
  • +
  • key + string Key sequence (Eg: `j`) +
  • +
  • action + function + Function to run when keymap is triggered +
  • +
+ + + + +

Usage:

+
    +
    web.keymap.set('n', 'o', function()
    +  web.view.create('https://google.com')
    +end)
    +
+ +
+
+ + web.keymap.set_mode (mode) +
+
+ Set the current keymap mode + + +

Parameters:

+
    +
  • mode + string + The keymap mode to set +
  • +
+ + + + +

Usage:

+
    +
    web.keymap.set_mode('n') -- Set to normal mode
    +web.keymap.set_mode('i') -- Set to insert mode
    +
+ +
+
+ + web.keymap.get_mode () +
+
+ Get the current keymap mode + + + + + + +

Usage:

+
    +
    local current_mode = web.keymap.get_mode()
    +
+ +
+
+ + web.view.close (view_id) +
+
+ Close view + + +

Parameters:

+
    +
  • view_id + ? number View id to close +
  • +
+ + + + +

Usage:

+
    +
    web.view.close()  -- Close current view in active window
    +web.view.close(3) -- Close view with id 3
    +
+ +
+
+ + web.view.create (url) +
+
+ Create a new view with a url + + +

Parameters:

+
    +
  • url + string Url to open in the new view +
  • +
+ + + + +

Usage:

+
    +
    web.view.create('https://duckduckgo.com') -- Opens url in new view
    +web.view.create() -- Opens new_view_url by default
    +
+ +
+
+ + web.view.current () +
+
+ Get current view id + + + +

Returns:

+
    + + number + _id Current view id +
+ + + +

Usage:

+
    +
    local view_id = web.view.current()
    +
+ +
+
+ + web.view.list () +
+
+ Get a list of views in the current window + + + +

Returns:

+
    + + table + List of views +
+ + + +

Usage:

+
    +
    local views = web.view.list()
    +print(views[1].url, views[1].title, views[1].id)
    +
+ +
+
+ + web.view.select (view_id) +
+
+ Select a view in current window + + +

Parameters:

+
    +
  • view_id + number + View id to select +
  • +
+ + + + +

Usage:

+
    +
    web.view.select(3) -- Select view with id 3
    +
+ +
+
+ + web.view.set_url (url, view_id) +
+
+ Set url of a given view + + +

Parameters:

+
    +
  • url + string + Url to open +
  • +
  • view_id + number + View id to select +
  • +
+ + + + +

Usage:

+
    +
    web.view.set_url('https://foobar.com')
    +web.view.set_url('https://foobar.com', 3) -- Set url for view with id 3
    +
+ +
+
+ + web.view.set_html (html, opts) +
+
+ Set html inside the page for a given view + + +

Parameters:

+
    +
  • html + string HTML string +
  • +
  • opts table Options +
      +
    • view + number View id +
    • +
    +
+ + + + +

Usage:

+
    +
    web.view.set_html('<h2>HJello</h2>')
    +web.view.set_html('<h2>HJello</h2>', { view = 3 }) -- Set html for view with id 3
    +
+ +
+
+ + web.view.run_js (js, opts) +
+
+ Run js in a view + + +

Parameters:

+
    +
  • js + string + HTML string +
  • +
  • opts + ? RunJSOpts Options +
  • +
+ + + + +

Usage:

+
    +
    web.view.run_js('console.log(42)')
    +web.view.run_js('console.log(42)', { view = 3 }) -- Set html for view with id 3
    +
+ +
+
+ + web.view.reload (opts) +
+
+ Relaod a given view + + +

Parameters:

+
    +
  • opts + ? ReloadOpts Options +
  • +
+ + + + +

Usage:

+
    +
    web.view.reload()
    +web.view.reload({ view = 3 }) -- Reload view with id 3
    +
+ +
+
+ + web.view.expose (name, action, opts) +
+
+ Expose a lua function inside a view (Only works with decorations) + + +

Parameters:

+
    +
  • name + string Func name +
  • +
  • action + fun(table):nil Action to call when function is invoked in view +
  • +
  • opts + ExposeOpts? Options +
  • +
+ + + + +

Usage:

+
    +
  • web.view.expose('tabSelect', function(args)
    +  web.view.select(tonumber(args.view))
    +end)
  • +
  • -- In javascript
    +_nullbrowser.rpc.tabSelect({ view: 5 })
  • +
+ +
+
+ + web.view.open_devtools (view_id) +
+
+ Open devtools window for the view + + +

Parameters:

+
    +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.view.open_devtools() -- Open devtools window for current view
    +web.view.open_devtools(5) -- Open devtools window for view id 5
    +
+ +
+
+ + web.view.current_index () +
+
+ Get current view index + + + +

Returns:

+
    + + number + |nil index Current view index +
+ + + +

Usage:

+
    +
    local index = web.view.current_index()
    +
+ +
+
+ + web.event.add_listener (events, opts) +
+
+ Listen to events from the browser + + +

Parameters:

+
    +
  • events + string + |table Event or events to listen to +
  • +
  • opts Options +
      +
    • callback + fun(opts:any):nil Callback called when that event occurs +
    • +
    +
+ + + + +

Usage:

+
    +
    web.event.add_listener('UrlChanged', {
    +  callback = function(opts)
    +    print(opts.url, opts.tab, opts.win)
    +  end,
    +})
    +
+ +
+
+ + set (key, value) +
+
+ Set configuration options + + +

Parameters:

+
    +
  • key + string + The name of the configuration +
  • +
  • value + nil + |string|boolean|number Configuration value +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    web.set('new_view_url', 'https://duckduckgo.com')
    +-- Can also be written as
    +web.opts.new_view_url = 'https://duckduckgo.com'
    +
+ +
+
+ + get (key) +
+
+ Get configuration value + + +

Parameters:

+
    +
  • key + string + The name of the configuration +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    local url = web.get('new_view_url')
    +
+ +
+
+ + web.history.back (count, view_id) +
+
+ Go back in history for given view + + +

Parameters:

+
    +
  • count + number? Number of history items to go back in (default = 1) +
  • +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.history.back(2, 3) -- Go back 2 history items for view id 3
    +
+ +
+
+ + web.history.forward (count, view_id) +
+
+ Go forward in history for given view + + +

Parameters:

+
    +
  • count + number? Number of history items to go forward in (default = 1) +
  • +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.history.forward(2, 3) -- Go forward 2 history items for view id 3
    +
+ +
+
+ + web.search.set_text (text, view_id) +
+
+ Search text inside a view + + +

Parameters:

+
    +
  • text + string? Text to search +
  • +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.search.set_text('whatever') -- Search in current view
    +web.search.set_text('whatever', 5) -- Search in view id 5
    +
+ +
+
+ + web.search.reset (view_id) +
+
+ Reset searched text in a view (Same as web.search.set_text('')) + + +

Parameters:

+
    +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.search.reset() -- Reset search state for current view
    +web.search.reset(5) -- Reset search state for view id 5
    +
+ +
+
+ + web.search.get_text () +
+
+ Get the last searched text + + + + + + +

Usage:

+
    +
    local text = web.search.get_text()
    +
+ +
+
+ + web.search.next (view_id) +
+
+ Highlight next search term for the last searched text + + +

Parameters:

+
    +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.search.next() -- Next search result in current view
    +web.search.next(5) -- Next search result in view id 5
    +
+ +
+
+ + web.search.previous (view_id) +
+
+ Highlight previous search term for the last searched text + + +

Parameters:

+
    +
  • view_id + number + Id of the view +
  • +
+ + + + +

Usage:

+
    +
    web.search.previous() -- Previous search result in current view
    +web.search.previous(5) -- Previous search result in view id 5
    +
+ +
+
+ + web.view.scroll (deltax, deltay, view_id) +
+
+ TODO: Document + + +

Parameters:

+
    +
  • deltax + +
  • +
  • deltay + +
  • +
  • view_id + +
  • +
+ + + + + +
+
+ + web.view.scroll_to_top (view_id) +
+
+ TODO: Document + + +

Parameters:

+
    +
  • view_id + +
  • +
+ + + + + +
+
+ + web.view.scroll_to_bottom (view_id) +
+
+ TODO: Document + + +

Parameters:

+
    +
  • view_id + +
  • +
+ + + + + +
+
+ + web.utils.string_trim (str) +
+
+ Trim whitespace from start and end of a string + + +

Parameters:

+ + +

Returns:

+
    + + string + +
+ + + + +
+
+ + web.utils.table_merge (tbl) +
+
+ Merge multiple tables + + +

Parameters:

+ + +

Returns:

+
    + + table + +
+ + + + +
+
+ + web.utils.table_keys (tbl) +
+
+ Get keys of a table + + +

Parameters:

+ + +

Returns:

+
    + + table + +
+ + + + +
+
+ + web.utils.equals (a, b) +
+
+ Check if 2 values are deeply equal + + +

Parameters:

+
    +
  • a + any + +
  • +
  • b + any + +
  • +
+ +

Returns:

+
    + + boolean + +
+ + + + +
+
+

Tables

+ +
+
+ + WebOpts +
+
+ Maps to values defined in ./src/Configuration.hpp + + +

Fields:

+
    +
  • app_data_dir + string (readonly) Directory where app data is stored +
  • +
  • close_window_when_no_views + boolean If true, when the last tab in a window is closed, the window closes (default: true) +
  • +
  • config_dir + string (readonly) Directory where app config is stored +
  • +
  • downloads_dir + string Directory where downloaded files go +
  • +
  • new_view_url + string URL used when view url is not specified (default: 'https://duckduckgo.com') +
  • +
  • permissions_persistance + 'always'|'session'|'never' How to persist choices for permissions (default: 'always') +
  • +
  • user_agent + string User agent sent by the browser +
  • +
+ + + + + +
+
+

Fields

+ +
+
+ + _G.__internals +
+
+ Internal api (unstable) + + + + + + + +
+
+ + opts +
+
+ API for configuring browser options + + + + + +

See also:

+ + +

Usage:

+
    +
    web.opts.new_view_url = 'https://duckduckgo.com'
    +
+ +
+
+ + uv +
+
+ luv api (https://github.com/luvit/luv/blob/master/docs.md) + + + + + + + +
+
+ + inspect +
+
+ Returns human-readable string representation of Lua tables (https://github.com/kikito/inspect.lua) + + +
    +
  • value + any + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.5.0 +Last updated 1980-01-01 00:00:00 +
+
+ + diff --git a/doc/ldoc.css b/doc/ldoc.css new file mode 100644 index 0000000..f945ae7 --- /dev/null +++ b/doc/ldoc.css @@ -0,0 +1,304 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 20px 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color: #f0f0f0; + border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color: #f0f0f0; + overflow: visible; +} + +#navigation h2 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + width: 700px; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; min-width: 200px; } +table.module_list td.summary { width: 100%; } + + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f0f0f0; min-width: 200px; } +table.function_list td.summary { width: 100%; } + +ul.nowrap { + overflow:auto; + white-space:nowrap; +} + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + + +/* styles for prettification of source */ +pre .comment { color: #558817; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #aa5050; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #8080ff; } +pre .number { color: #f8660d; } +pre .function-name { color: #60447f; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #800080; } +pre .user-keyword { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } + diff --git a/flake.nix b/flake.nix index 4ab2f01..82ec5a8 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,7 @@ gdb valgrind go-grip + luajitPackages.ldoc ] ++ dependencies; LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath buildInputs}"; diff --git a/init.lua b/init.lua index f351ca8..ae1f181 100644 --- a/init.lua +++ b/init.lua @@ -14,7 +14,7 @@ local search_engines = require 'null-browser.extras.search-engines' search_engines.urls['ld'] = 'https://lite.duckduckgo.com/?q={}' search_engines.urls['g'] = 'https://github.com/{}' search_engines.urls['y'] = 'https://youtube.com/results?search_query={}' -search_engines.urls['r'] = 'https://reddit.com/{}' +search_engines.urls['r'] = 'https://reddit.com/r/{}' local Dmenu = require 'null-browser.extras.dmenu' local menu = Dmenu:new { @@ -55,7 +55,9 @@ web.event.add_listener('NotificationReceived', { }) -- Tabline -require 'null-browser.extras.tabline'.init() +require 'null-browser.extras.tabline'.init { + decoration = web.decorations.top, +} -- Statusline require 'null-browser.extras.statusline'.init { diff --git a/lua/null-browser/api.lua b/lua/null-browser/api.lua index e1f2acc..6d6f974 100644 --- a/lua/null-browser/api.lua +++ b/lua/null-browser/api.lua @@ -1,8 +1,10 @@ ---- Internal api (unstable) ---- @type table -__internals = __internals +---@diagnostic disable: doc-field-no-class, undefined-doc-param +--- Lua api for configuring null browser. +--- @module web + ---- @type table +--- Internal api (unstable) +_G.__internals = _G.__internals _G.web = _G.web or {} web.search = web.search or {} web.keymap = web.keymap or {} @@ -13,7 +15,9 @@ web.decorations = web.decorations or {} require 'null-browser.utils' ---- @param fn fun(): nil Schedule a function to be called on next tick (qt+libuv event loop) +--- Schedule a function to be called on next tick (qt+libuv event loop) +--- +--- @param fn fun():nil Function to call function web.schedule(fn) __internals.schedule(fn) end --- Add a keymap @@ -22,111 +26,89 @@ function web.schedule(fn) __internals.schedule(fn) end --- @param key string Key sequence (Eg: `j`) --- @param action function Function to run when keymap is triggered --- ---- @example ---- ```lua +--- @usage --- web.keymap.set('n', 'o', function() --- web.view.create('https://google.com') --- end) ---- ``` function web.keymap.set(mode, key, action) return __internals.keymap_set(mode, key, action) end --- Set the current keymap mode --- --- @param mode string The keymap mode to set --- ---- @example ---- ```lua +--- @usage --- web.keymap.set_mode('n') -- Set to normal mode --- web.keymap.set_mode('i') -- Set to insert mode ---- ``` function web.keymap.set_mode(mode) return __internals.keymap_set_mode(mode) end --- Get the current keymap mode --- ---- @example ---- ```lua +--- @usage --- local current_mode = web.keymap.get_mode() ---- ``` function web.keymap.get_mode() return __internals.keymap_get_mode() end --- Close view --- --- @param view_id? number View id to close --- ---- @example ---- ```lua +--- @usage --- web.view.close() -- Close current view in active window --- web.view.close(3) -- Close view with id 3 ---- ``` function web.view.close(view_id) return __internals.view_close(view_id) end --- Create a new view with a url --- --- @param url string Url to open in the new view --- ---- @example ---- ```lua +--- @usage --- web.view.create('https://duckduckgo.com') -- Opens url in new view --- web.view.create() -- Opens new_view_url by default ---- ``` function web.view.create(url) return __internals.view_create(url) end --- Get current view id --- --- @return number view_id Current view id --- ---- @example ---- ```lua +--- @usage --- local view_id = web.view.current() ---- ``` function web.view.current() return __internals.view_current() end --- Get a list of views in the current window --- --- @return table views List of views --- ---- @example ---- ```lua +--- @usage --- local views = web.view.list() --- print(views[1].url, views[1].title, views[1].id) ---- ``` function web.view.list() return __internals.view_list() end --- Select a view in current window --- --- @param view_id number View id to select --- ---- @example ---- ```lua +--- @usage --- web.view.select(3) -- Select view with id 3 ---- ``` function web.view.select(view_id) return __internals.view_select(view_id) end --- Set url of a given view --- --- @param url string Url to open ---- @param view_id? number View id to select +--- @param view_id number? View id to select --- ---- @example ---- ```lua +--- @usage --- web.view.set_url('https://foobar.com') --- web.view.set_url('https://foobar.com', 3) -- Set url for view with id 3 ---- ``` function web.view.set_url(url, view_id) return __internals.view_set_url(url, view_id) end ---- @class SetHTMLOpts ---- @field view? number View id - ---- Set html in a given view +--- Set html inside the page for a given view --- ---- @param html string HTML string ---- @param opts? SetHTMLOpts Options +--- @param html string HTML string +--- @param opts table Options +--- @param opts.view number View id --- ---- @example ---- ```lua +--- @usage --- web.view.set_html('

HJello

') --- web.view.set_html('

HJello

', { view = 3 }) -- Set html for view with id 3 ---- ``` function web.view.set_html(html, opts) return __internals.view_set_html(html, (opts or {}).view) end --- @class RunJSOpts @@ -138,11 +120,9 @@ function web.view.set_html(html, opts) return __internals.view_set_html(html, (o --- @param js string HTML string --- @param opts? RunJSOpts Options --- ---- @example ---- ```lua +--- @usage --- web.view.run_js('console.log(42)') --- web.view.run_js('console.log(42)', { view = 3 }) -- Set html for view with id 3 ---- ``` function web.view.run_js(js, opts) return __internals.view_run_js(js, opts or {}) end --- @class ReloadOpts @@ -150,13 +130,11 @@ function web.view.run_js(js, opts) return __internals.view_run_js(js, opts or {} --- Relaod a given view --- ---- @param opts? RunJSOpts Options +--- @param opts? ReloadOpts Options --- ---- @example ---- ```lua +--- @usage --- web.view.reload() --- web.view.reload({ view = 3 }) -- Reload view with id 3 ---- ``` function web.view.reload(opts) return __internals.view_reload((opts or {}).view) end --- @class ExposeOpts @@ -164,41 +142,35 @@ function web.view.reload(opts) return __internals.view_reload((opts or {}).view) --- Expose a lua function inside a view (Only works with decorations) --- ---- @param name string Func name ---- @param action fun(table):nil Action to call when function is invoked in view ---- @param opts? ExposeOpts Options +--- @param name string Func name +--- @param action fun(table):nil Action to call when function is invoked in view +--- @param opts ExposeOpts? Options --- ---- @example ---- ```lua ---- web.view.expose('tab_select', function(args) +--- @usage +--- web.view.expose('tabSelect', function(args) --- web.view.select(tonumber(args.view)) --- end) ---- ``` ---- then in js ---- ```js ---- _nullbrowser.rpc.tab_select({ view: 5 }) ---- ``` +--- +--- @usage +--- -- In javascript +--- _nullbrowser.rpc.tabSelect({ view: 5 }) function web.view.expose(name, action, opts) return __internals.view_expose(name, action, (opts or {}).view) end --- Open devtools window for the view --- ---- @param view_id? number Id of the view +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.view.open_devtools() -- Open devtools window for current view --- web.view.open_devtools(5) -- Open devtools window for view id 5 ---- ``` function web.view.open_devtools(view_id) return __internals.view_open_devtools(view_id) end --- Get current view index --- --- @return number|nil index Current view index --- ---- @example ---- ```lua +--- @usage --- local index = web.view.current_index() ---- ``` function web.view.current_index() local current_view = web.view.current(); for index, view in ipairs(web.view.list()) do @@ -210,21 +182,16 @@ function web.view.current_index() end --- Listen to events from the browser +--- @param events string|table Event or events to listen to +--- @param opts table Options +--- @param opts.callback fun(opts:any):nil Callback called when that event occurs --- ---- @class nullb.EventListenerOptions ---- @field callback any Callback called when that event occurs ---- ---- @param events string|table Event or events to listen to ---- @param opts nullb.EventListenerOptions Options ---- ---- @example ---- ```lua +--- @usage --- web.event.add_listener('UrlChanged', { --- callback = function(opts) --- print(opts.url, opts.tab, opts.win) --- end, --- }) ---- ``` function web.event.add_listener(events, opts) opts = web.utils.table_merge({}, opts or {}) if type(events) == "string" then events = { events } end @@ -234,17 +201,41 @@ function web.event.add_listener(events, opts) end --- Set configuration options +--- @see WebOpts --- --- @param key string The name of the configuration --- @param value nil|string|boolean|number Configuration value --- ---- @example ---- ```lua +--- @usage --- web.set('new_view_url', 'https://duckduckgo.com') ---- ``` +--- -- Can also be written as +--- web.opts.new_view_url = 'https://duckduckgo.com' function web.set(key, value) __internals.config_set(key, value) end ---- Web options. Calls web.set/web.get for options +--- Get configuration value +--- @see WebOpts +--- +--- @param key string The name of the configuration +--- +--- @usage +--- local url = web.get('new_view_url') +function web.get(key) return __internals.config_get(key) end + +--- Maps to values defined in ./src/Configuration.hpp +--- @table WebOpts +--- @field app_data_dir string (readonly) Directory where app data is stored +--- @field close_window_when_no_views boolean If true, when the last tab in a window is closed, the window closes (default: true) +--- @field config_dir string (readonly) Directory where app config is stored +--- @field downloads_dir string Directory where downloaded files go +--- @field new_view_url string URL used when view url is not specified (default: 'https://duckduckgo.com') +--- @field permissions_persistance 'always'|'session'|'never' How to persist choices for permissions (default: 'always') +--- @field user_agent string User agent sent by the browser + +--- API for configuring browser options +--- @see WebOpts +--- +--- @usage +--- web.opts.new_view_url = 'https://duckduckgo.com' web.opts = setmetatable({}, { __index = function(_, key) return web.get(key) @@ -254,89 +245,65 @@ web.opts = setmetatable({}, { end, }) ---- Get configuration value ---- ---- @param key string The name of the configuration ---- ---- @example ---- ```lua ---- local url = web.get('new_view_url') ---- ``` -function web.get(key) return __internals.config_get(key) end - --- Go back in history for given view --- ---- @param count? number Number of history items to go back in (default = 1) ---- @param view_id? number Id of the view +--- @param count number? Number of history items to go back in (default = 1) +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.history.back(2, 3) -- Go back 2 history items for view id 3 ---- ``` function web.history.back(count, view_id) return __internals.history_back(count, view_id) end --- Go forward in history for given view --- ---- @param count? number Number of history items to go forward in (default = 1) ---- @param view_id? number Id of the view +--- @param count number? Number of history items to go forward in (default = 1) +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.history.forward(2, 3) -- Go forward 2 history items for view id 3 ---- ``` function web.history.forward(count, view_id) return __internals.history_forward(count, view_id) end --- Search text inside a view --- ---- @param text string Text to search ---- @param view_id? number Id of the view +--- @param text string? Text to search +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.search.set_text('whatever') -- Search in current view --- web.search.set_text('whatever', 5) -- Search in view id 5 ---- ``` function web.search.set_text(text, view_id) return __internals.search_set_text(text, view_id) end --- Reset searched text in a view (Same as web.search.set_text('')) --- ---- @param view_id? number Id of the view +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.search.reset() -- Reset search state for current view --- web.search.reset(5) -- Reset search state for view id 5 ---- ``` function web.search.reset(view_id) return __internals.search_set_text('', view_id) end --- Get the last searched text --- ---- @example ---- ```lua +--- @usage --- local text = web.search.get_text() ---- ``` function web.search.get_text() return __internals.search_get_text() end --- Highlight next search term for the last searched text --- ---- @param view_id? number Id of the view +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.search.next() -- Next search result in current view --- web.search.next(5) -- Next search result in view id 5 ---- ``` function web.search.next(view_id) return __internals.search_next(view_id) end --- Highlight previous search term for the last searched text --- ---- @param view_id? number Id of the view +--- @param view_id number? Id of the view --- ---- @example ---- ```lua +--- @usage --- web.search.previous() -- Previous search result in current view --- web.search.previous(5) -- Previous search result in view id 5 ---- ``` function web.search.previous(view_id) return __internals.search_previous(view_id) end --- TODO: Document @@ -348,19 +315,19 @@ function web.view.scroll_to_top(view_id) return __internals.view_scroll_to_top(v --- TODO: Document function web.view.scroll_to_bottom(view_id) return __internals.view_scroll_to_bottom(view_id) end ---- Decoration api ---- --- @class DecorationOpts --- @field win? number ---- + --- @class Decoration --- @field enable fun(opts?: DecorationOpts): nil --- @field disable fun(opts?: DecorationOpts): nil --- @field set_enabled fun(enabled: boolean, opts?: DecorationOpts): nil --- @field is_enabled fun(opts?: DecorationOpts): boolean --- @field view fun(opts?: DecorationOpts): number|nil ---- ---- @alias DecorationType number + +--- @class DecorationType: number + +--- Decoration api --- --- @param type DecorationType --- @return Decoration @@ -381,12 +348,10 @@ local function create_decoration_api(type) } end ---- @see DecorationType in ./src/widgets/Decorations.hpp +--- Maps to values defined in ./src/widgets/Decorations.hpp local DecorationType = { top = 1, bottom = 2, left = 3, right = 4 } web.decorations.top = create_decoration_api(DecorationType.top) web.decorations.bottom = create_decoration_api(DecorationType.bottom) web.decorations.left = create_decoration_api(DecorationType.left) web.decorations.right = create_decoration_api(DecorationType.right) - -print("api loaded") diff --git a/lua/null-browser/extras/tabline.lua b/lua/null-browser/extras/tabline.lua index e265940..9c53f41 100644 --- a/lua/null-browser/extras/tabline.lua +++ b/lua/null-browser/extras/tabline.lua @@ -72,6 +72,9 @@ function tabline.css() align-items: stretch; height: 100vh; } + .tabs.vertical { + flex-direction: column; + } .tab { all: unset; flex: 1; diff --git a/lua/null-browser/utils.lua b/lua/null-browser/utils.lua index 13b9d13..77ed60f 100644 --- a/lua/null-browser/utils.lua +++ b/lua/null-browser/utils.lua @@ -1,37 +1,46 @@ ---- @type table +--- Helper lua utils for null browser +--- @module web + _G.web = _G.web or {} web.utils = web.utils or {} ---- luv api ---- @type table ---- @link https://github.com/luvit/luv/blob/master/docs.md +--- luv api (https://github.com/luvit/luv/blob/master/docs.md) +--- --- @diagnostic disable-next-line: undefined-global web.uv = web.uv or nil local inspector = require 'null-browser.inspect' ---- Returns human-readable string representation of Lua tables ---- ---- @link https://github.com/kikito/inspect.lua +--- Returns human-readable string representation of Lua tables (https://github.com/kikito/inspect.lua) +--- @diagnostic disable-next-line: undefined-doc-param +--- @param value any +--- @return string web.inspect = inspector.inspect --- TODO: Documentation +--- Trim whitespace from start and end of a string +--- @param str string +--- @return string function web.utils.string_trim(str) local res, _ = string.gsub(str, '^%s*(.-)%s*$', '%1') return res end --- TODO: Documentation -function web.utils.table_merge(t, ...) +--- Merge multiple tables +--- @param tbl table +--- @return table +function web.utils.table_merge(tbl, ...) for i = 1, select("#", ...) do for k, v in pairs(select(i, ...) or {}) do - t[k] = v + tbl[k] = v end end - return t + return tbl end +--- Get keys of a table +--- @param tbl table +--- @return table function web.utils.table_keys(tbl) local keys = {} for key, _ in pairs(tbl) do @@ -63,6 +72,10 @@ local function is_deep_equal_helper(a, b, table_pairs) return a == b end +--- Check if 2 values are deeply equal +--- @param a any +--- @param b any +--- @return boolean function web.utils.equals(a, b) return is_deep_equal_helper(a, b, {}) end -- cgit v1.3.1