From 7ee44a1673ae48e7783fb8767479b4daefb6d60a Mon Sep 17 00:00:00 2001 From: Mikhail Korobov Date: Wed, 18 Feb 2015 02:07:30 +0500 Subject: [PATCH] SHIFT+TAB shows help for splash methods and attributes --- MANIFEST.in | 5 +- docs/scripting-ref.rst | 12 + scripts/rst2inspections.py | 70 +++++ setup.py | 3 + splash/kernel/completer.py | 3 + splash/kernel/inspections.py | 98 +++++++ splash/kernel/inspections/README.rst | 4 + splash/kernel/inspections/splash-auto.json | 302 +++++++++++++++++++++ splash/kernel/kernel.py | 5 + splash/kernel/lua_parser.py | 40 ++- splash/tests/test_lua_parser.py | 14 + 11 files changed, 545 insertions(+), 11 deletions(-) create mode 100755 scripts/rst2inspections.py create mode 100644 splash/kernel/inspections.py create mode 100644 splash/kernel/inspections/README.rst create mode 100644 splash/kernel/inspections/splash-auto.json diff --git a/MANIFEST.in b/MANIFEST.in index c19763689..e76ac0e25 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,7 +5,10 @@ include docs/make.bat include docs/conf.py include requirements.txt +recursive-include scripts *.py recursive-include docs *.rst -recursive-include splash/lua_modules *.lua +recursive-include splash/lua_modules *.lua *.md *.rst *.txt recursive-include splash/tests *.txt *.js *.ini *.lua recursive-include splash/vendor/harviewer/webapp *.js *.html *.css *.gif *.png *.swf *.html +recursive-include splash/kernel/inspections *.json +recursive-include splash/kernel/kernels *.json diff --git a/docs/scripting-ref.rst b/docs/scripting-ref.rst index ca2814a27..f405e1a46 100644 --- a/docs/scripting-ref.rst +++ b/docs/scripting-ref.rst @@ -1004,6 +1004,8 @@ Replace all current cookies with the passed ``cookies``. * cookies - a Lua table with all cookies to set, in the same format as :ref:`splash-get-cookies` returns. +**Returns:** nil. + Example 1 - save and restore cookies: .. code-block:: lua @@ -1106,6 +1108,8 @@ Set Content-Type of a result returned to a client. * content_type - a string with Content-Type header value. +**Returns:** nil. + If a table is returned by "main" function then ``splash:set_result_content_type`` has no effect: Content-Type of the result is set to ``application/json``. @@ -1144,6 +1148,8 @@ Enable/disable images. * enabled - ``true`` to enable images, ``false`` to disable them. +**Returns:** nil. + By default, images are enabled. Disabling of the images can save a lot of network traffic (usually around ~50%) and make rendering faster. Note that this option can affect the JavaScript code inside page: @@ -1193,6 +1199,8 @@ Set the browser viewport size. * width - integer, requested viewport width in pixels; * height - integer, requested viewport height in pixels. +**Returns:** nil. + This will change the size of the visible area and subsequent rendering commands, e.g., :ref:`splash-png`, will produce an image with the specified size. @@ -1262,6 +1270,8 @@ Overwrite the User-Agent header for all further requests. * value - string, a value of User-Agent HTTP header. +**Returns:** nil. + .. _splash-set-custom-headers: splash:set_custom_headers @@ -1275,6 +1285,8 @@ Set custom HTTP headers to send with each request. * headers - a Lua table with HTTP headers. +**Returns:** nil. + Headers are merged with WebKit default headers, overwriting WebKit values in case of conflicts. diff --git a/scripts/rst2inspections.py b/scripts/rst2inspections.py new file mode 100755 index 000000000..20596f020 --- /dev/null +++ b/scripts/rst2inspections.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +This script extracts inspections info for IPython kernel from +Splash reference documentation. +""" +from __future__ import absolute_import +import os +import re +import json +import collections + + +def _parse_doc(doc): + res = collections.OrderedDict() + + m = re.search("^splash:(\w+)\s+[-]+\s*$", doc, re.MULTILINE) + res['name'] = m.group(1) if m else None + + header, content = re.split("[-][-]+", doc, maxsplit=1) + res['header'] = header.strip() + res['content'] = content.strip() + + m = re.search(r"((.|[\n\r])+?)\*\*Signature", content, re.MULTILINE) + res['short'] = m.group(1).strip() if m else None + + m = re.search(r"Signature:.*``(.+)``", content) + res['signature'] = m.group(1) if m else None + + m = re.search(r"Returns:\*\*((.|[\n\r])+?)\n\n", content, re.MULTILINE) + res['returns'] = m.group(1).strip() if m else None + + m = re.search(r"(?:.|[\n\r])*:\*\*(?:.|[\n\r])+?\n\n((?:.|[\n\r])+)", content, re.MULTILINE) + res['details'] = m.group(1).strip() if m else None + + m = re.search(r"Parameters:\*\*((.|[\n\r])+?)\*\*Returns:", content, re.MULTILINE) + res['params'] = m.group(1).strip() if m else None + + return res + + +def parse_rst(rst_source): + """ + Parse Sphinx Lua splash methods reference docs and + extract information useful for inspections. + """ + parsed = re.split("\.\. _splash-(.+):", rst_source)[1:] + # ids = parsed[::2] + docs = parsed[1::2] + info = [_parse_doc(d) for d in docs] + return collections.OrderedDict( + (d["header"], d) + for d in info + ) + + +def rst2inspections(rst_filename, out_filename): + with open(rst_filename, "rb") as f: + info = parse_rst(f.read()) + + with open(out_filename, "wb") as f: + json.dump(info, f, indent=2) + + +if __name__ == '__main__': + root = os.path.join(os.path.dirname(__file__), "..") + rst_filename = os.path.join(root, "docs", "scripting-ref.rst") + out_filename = os.path.join(root, "splash", "kernel", "inspections", "splash-auto.json") + rst2inspections(rst_filename, out_filename) + diff --git a/setup.py b/setup.py index a9268cccd..064e6df3c 100755 --- a/setup.py +++ b/setup.py @@ -47,6 +47,9 @@ def get_version(): 'vendor/harviewer/webapp/har.js', 'lua_modules/*.lua', + 'lua_modules/vendor/*.lua', + 'kernel/inspections/*.json', + 'kernel/kernels/splash/*.json', ]}, 'classifiers': [ 'Programming Language :: Python', diff --git a/splash/kernel/completer.py b/splash/kernel/completer.py index 91fb664ce..926ca0604 100644 --- a/splash/kernel/completer.py +++ b/splash/kernel/completer.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- +""" +Autocompleter for Lua code. +""" from __future__ import absolute_import import string diff --git a/splash/kernel/inspections.py b/splash/kernel/inspections.py new file mode 100644 index 000000000..974109824 --- /dev/null +++ b/splash/kernel/inspections.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +""" +Inspections for Lua code. +""" +from __future__ import absolute_import +import os +import glob +import json +from splash.kernel.lua_parser import ( + LuaParser, + SplashMethod, + SplashMethodOpenBrace, + SplashAttribute +) + + +class Inspector(object): + """ Inspector for Lua code """ + def __init__(self, lua): + self.lua = lua + self.docs = _SplashDocs() + self.parser = LuaParser(lua) + + def parse(self, code, cursor_pos): + return self.parser.parse(code, cursor_pos) + + def doc_repr(self, doc): + if not doc.get("signature"): + return doc["content"] + + parts = [doc["signature"]] + if doc.get('short'): + parts += [doc["short"]] + + if doc.get('params'): + parts += ["Parameters:\n\n" + doc["params"]] + + if doc.get('returns'): + parts += ["Returns: " + doc["returns"]] + + if doc.get('details'): + parts += [doc["details"]] + + return "\n\n".join(parts) + + def help(self, code, cursor_pos, detail_level): + # from .completer import _pp + + NO_RESULT = { + 'status': 'ok', + 'data': {}, + 'metadata': {}, + 'found': False, + } + + m = self.parse(code, cursor_pos) + if m is None: + return NO_RESULT + + doc = None + + if isinstance(m, (SplashMethod, SplashMethodOpenBrace)): + name = "splash:" + m.prefix + doc = self.docs.get(name) + + elif isinstance(m, SplashAttribute): + name = "splash." + m.prefix + doc = self.docs.get(name) + + if doc is None: + return NO_RESULT + + return { + 'status': 'ok', + 'data': {"text/plain": self.doc_repr(doc)}, + 'metadata': {}, + 'found': True, + } + + +class _SplashDocs(object): + def __init__(self, folder=None): + if folder is None: + folder = os.path.join(os.path.dirname(__file__), "inspections") + + self.info = {} + files = sorted(glob.glob(folder + "/*.json")) + for name in files: + full_name = os.path.join(folder, name) + with open(full_name, "rb") as f: + info = json.load(f, encoding='utf8') + self.info.update(info) + + def __getitem__(self, item): + return self.info[item] + + def get(self, key, default=None): + return self.info.get(key, default) diff --git a/splash/kernel/inspections/README.rst b/splash/kernel/inspections/README.rst new file mode 100644 index 000000000..6ab529c33 --- /dev/null +++ b/splash/kernel/inspections/README.rst @@ -0,0 +1,4 @@ +A folder with inspection data for Splash IPython kernel. + +:file:`splash-auto.json` is generated from reference documentation using +:file:`scripts/rst2inspections.py` script. diff --git a/splash/kernel/inspections/splash-auto.json b/splash/kernel/inspections/splash-auto.json new file mode 100644 index 000000000..770ab3f82 --- /dev/null +++ b/splash/kernel/inspections/splash-auto.json @@ -0,0 +1,302 @@ +{ + "splash:go": { + "name": "go", + "header": "splash:go", + "content": "Go to an URL. This is similar to entering an URL in a browser\naddress bar, pressing Enter and waiting until page loads.\n\n**Signature:** ``ok, reason = splash:go{url, baseurl=nil, headers=nil}``\n\n**Parameters:**\n\n* url - URL to load;\n* baseurl - base URL to use, optional. When ``baseurl`` argument is passed\n the page is still loaded from ``url``, but it is rendered as if it was\n loaded from ``baseurl``: relative resource paths will be relative\n to ``baseurl``, and the browser will think ``baseurl`` is in address bar;\n* headers - a Lua table with HTTP headers to add/replace in the initial request.\n\n**Returns:** ``ok, reason`` pair. If ``ok`` is nil then error happened during\npage load; ``reason`` provides an information about error type.\n\nThree types of errors are reported (``ok`` can be ``nil`` in 3 cases):\n\n1. There is nothing to render. This can happen if a host doesn't exist,\n server dropped connection, etc. In this case ``reason`` is ``\"error\"``.\n2. Server returned a response with 4xx or 5xx HTTP status code.\n ``reason`` is ``\"http\"`` in this case, i.e. for\n HTTP 404 Not Found ``reason`` is ``\"http404\"``.\n3. Navigation is locked (see :ref:`splash-lock-navigation`); ``reason``\n is ``\"navigation_locked\"``.\n\nError handling example:\n\n.. code-block:: lua\n\n local ok, reason = splash:go(\"http://example.com\")\n if not ok then\n if reason:sub(0,4) == 'http' then\n -- handle HTTP errors\n else\n -- handle other errors\n end\n end\n -- process the page\n\n -- assert can be used as a shortcut for error handling\n assert(splash:go(\"http://example.com\"))\n\nErrors (ok==nil) are only reported when \"main\" webpage request failed.\nIf a request to a related resource failed then no error is reported by\n``splash:go``. To detect and handle such errors (e.g. broken image/js/css\nlinks, ajax requests failed to load) use :ref:`splash-har`.\n\n``splash:go`` follows all HTTP redirects before returning the result,\nbut it doesn't follow HTML ```` redirects or\nredirects initiated by JavaScript code. To give the webpage time to follow\nthose redirects use :ref:`splash-wait`.\n\n``headers`` argument allows to add or replace default HTTP headers for the\ninitial request. To set custom headers for all further requests\n(including requests to related resources) use\n:ref:`splash-set-custom-headers`.\n\nCustom headers example:\n\n.. code-block:: lua\n\n local ok, reason = splash:go{\"http://example.com\", headers={\n [\"Custom-Header\"] = \"Header Value\",\n }})\n\nUser-Agent header is special: once used, it is kept for further requests.\nThis is an implementation detail and it could change in future releases;\nto set User-Agent header it is recommended to use\n:ref:`splash-set-user-agent` method.", + "short": "Go to an URL. This is similar to entering an URL in a browser\naddress bar, pressing Enter and waiting until page loads.", + "signature": "ok, reason = splash:go{url, baseurl=nil, headers=nil}", + "returns": "``ok, reason`` pair. If ``ok`` is nil then error happened during\npage load; ``reason`` provides an information about error type.", + "details": "Three types of errors are reported (``ok`` can be ``nil`` in 3 cases):\n\n1. There is nothing to render. This can happen if a host doesn't exist,\n server dropped connection, etc. In this case ``reason`` is ``\"error\"``.\n2. Server returned a response with 4xx or 5xx HTTP status code.\n ``reason`` is ``\"http\"`` in this case, i.e. for\n HTTP 404 Not Found ``reason`` is ``\"http404\"``.\n3. Navigation is locked (see :ref:`splash-lock-navigation`); ``reason``\n is ``\"navigation_locked\"``.\n\nError handling example:\n\n.. code-block:: lua\n\n local ok, reason = splash:go(\"http://example.com\")\n if not ok then\n if reason:sub(0,4) == 'http' then\n -- handle HTTP errors\n else\n -- handle other errors\n end\n end\n -- process the page\n\n -- assert can be used as a shortcut for error handling\n assert(splash:go(\"http://example.com\"))\n\nErrors (ok==nil) are only reported when \"main\" webpage request failed.\nIf a request to a related resource failed then no error is reported by\n``splash:go``. To detect and handle such errors (e.g. broken image/js/css\nlinks, ajax requests failed to load) use :ref:`splash-har`.\n\n``splash:go`` follows all HTTP redirects before returning the result,\nbut it doesn't follow HTML ```` redirects or\nredirects initiated by JavaScript code. To give the webpage time to follow\nthose redirects use :ref:`splash-wait`.\n\n``headers`` argument allows to add or replace default HTTP headers for the\ninitial request. To set custom headers for all further requests\n(including requests to related resources) use\n:ref:`splash-set-custom-headers`.\n\nCustom headers example:\n\n.. code-block:: lua\n\n local ok, reason = splash:go{\"http://example.com\", headers={\n [\"Custom-Header\"] = \"Header Value\",\n }})\n\nUser-Agent header is special: once used, it is kept for further requests.\nThis is an implementation detail and it could change in future releases;\nto set User-Agent header it is recommended to use\n:ref:`splash-set-user-agent` method.", + "params": "* url - URL to load;\n* baseurl - base URL to use, optional. When ``baseurl`` argument is passed\n the page is still loaded from ``url``, but it is rendered as if it was\n loaded from ``baseurl``: relative resource paths will be relative\n to ``baseurl``, and the browser will think ``baseurl`` is in address bar;\n* headers - a Lua table with HTTP headers to add/replace in the initial request." + }, + "splash:wait": { + "name": "wait", + "header": "splash:wait", + "content": "Wait for ``time`` seconds. When script is waiting WebKit continues\nprocessing the webpage.\n\n**Signature:** ``ok, reason = splash:wait{time, cancel_on_redirect=false, cancel_on_error=true}``\n\n**Parameters:**\n\n* time - time to wait, in seconds;\n* cancel_on_redirect - if true (not a default) and a redirect\n happened while waiting, then ``splash:wait`` stops earlier and returns\n ``nil, \"redirect\"``. Redirect could be initiated by\n ```` HTML tags or by JavaScript code.\n* cancel_on_error - if true (default) and an error which prevents page\n from being rendered happened while waiting (e.g. an internal WebKit error\n or a network error like a redirect to a non-resolvable host)\n then ``splash:wait`` stops earlier and returns ``nil, \"error\"``.\n\n**Returns:** ``ok, reason`` pair. If ``ok`` is ``nil`` then the timer was\nstopped prematurely, and ``reason`` contains a string with a reason.\nPossible reasons are ``\"error\"`` and ``\"redirect\"``.\n\nUsage example:\n\n.. code-block:: lua\n\n -- go to example.com, wait 0.5s, return rendered html, ignore all errors.\n function main(splash)\n splash:go(\"http://example.com\")\n splash:wait(0.5)\n return {html=splash:html()}\n end\n\nBy default wait timer continues to tick when redirect happens.\n``cancel_on_redirect`` option can be used to restart the timer after\neach redirect. For example, here is a function that waits for a given\ntime after each page load in case of redirects:\n\n.. code-block:: lua\n\n function wait_restarting_on_redirects(splash, time, max_redirects)\n local redirects_remaining = max_redirects\n while redirects_remaining do\n local ok, reason = self:wait{time=time, cancel_on_redirect=true}\n if reason ~= 'redirect' then\n return ok, reason\n end\n redirects_remaining = redirects_remaining - 1\n end\n return nil, \"too_many_redirects\"\n end", + "short": "Wait for ``time`` seconds. When script is waiting WebKit continues\nprocessing the webpage.", + "signature": "ok, reason = splash:wait{time, cancel_on_redirect=false, cancel_on_error=true}", + "returns": "``ok, reason`` pair. If ``ok`` is ``nil`` then the timer was\nstopped prematurely, and ``reason`` contains a string with a reason.\nPossible reasons are ``\"error\"`` and ``\"redirect\"``.", + "details": "Usage example:\n\n.. code-block:: lua\n\n -- go to example.com, wait 0.5s, return rendered html, ignore all errors.\n function main(splash)\n splash:go(\"http://example.com\")\n splash:wait(0.5)\n return {html=splash:html()}\n end\n\nBy default wait timer continues to tick when redirect happens.\n``cancel_on_redirect`` option can be used to restart the timer after\neach redirect. For example, here is a function that waits for a given\ntime after each page load in case of redirects:\n\n.. code-block:: lua\n\n function wait_restarting_on_redirects(splash, time, max_redirects)\n local redirects_remaining = max_redirects\n while redirects_remaining do\n local ok, reason = self:wait{time=time, cancel_on_redirect=true}\n if reason ~= 'redirect' then\n return ok, reason\n end\n redirects_remaining = redirects_remaining - 1\n end\n return nil, \"too_many_redirects\"\n end", + "params": "* time - time to wait, in seconds;\n* cancel_on_redirect - if true (not a default) and a redirect\n happened while waiting, then ``splash:wait`` stops earlier and returns\n ``nil, \"redirect\"``. Redirect could be initiated by\n ```` HTML tags or by JavaScript code.\n* cancel_on_error - if true (default) and an error which prevents page\n from being rendered happened while waiting (e.g. an internal WebKit error\n or a network error like a redirect to a non-resolvable host)\n then ``splash:wait`` stops earlier and returns ``nil, \"error\"``." + }, + "splash:jsfunc": { + "name": "jsfunc", + "header": "splash:jsfunc", + "content": "Convert JavaScript function to a Lua callable.\n\n**Signature:** ``lua_func = splash:jsfunc(func)``\n\n**Parameters:**\n\n* func - a string which defines a JavaScript function.\n\n**Returns:** a function that can be called from Lua to execute JavaScript\ncode in page context.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n local get_div_count = splash:jsfunc([[\n function (){\n var body = document.body;\n var divs = body.getElementsByTagName('div');\n return divs.length;\n }\n ]])\n\n splash:go(splash.args.url)\n return get_div_count()\n end\n\nNote how Lua ``[[ ]]`` string syntax is helpful here.\n\nJavaScript functions may accept arguments:\n\n.. code-block:: lua\n\n local vec_len = splash:jsfunc([[\n function(x, y) {\n return Math.sqrt(x*x + y*y)\n }\n ]])\n return {res=vec_len(5, 4)}\n\nGlobal JavaScript functions can be wrapped directly:\n\n.. code-block:: lua\n\n local pow = splash:jsfunc(\"Math.pow\")\n local twenty_five = pow(5, 2) -- 5^2 is 25\n local thousand = pow(10, 3) -- 10^3 is 1000\n\nLua strings, numbers, booleans and tables can be passed as arguments;\nthey are converted to JS strings/numbers/booleans/objects.\nCurrently it is not possible to pass other Lua objects. For example, it\nis not possible to pass a wrapped JavaScript function or a regular Lua function\nas an argument to another wrapped JavaScript function.\n\n.. _lua-js-conversion-rules:\n\nLua \u2192 JavaScript conversion rules:\n\n============== =================\nLua JavaScript\n============== =================\nstring string\nnumber number\nboolean boolean\ntable Object\nnil undefined\n============== =================\n\nFunction result is converted from JavaScript to Lua data type. Only simple\nJS objects are supported. For example, returning a function or a\nJQuery selector from a wrapped function won't work.\n\n.. _js-lua-conversion-rules:\n\nJavaScript \u2192 Lua conversion rules:\n\n============== =================\nJavaScript Lua\n============== =================\nstring string\nnumber number\nboolean boolean\nObject table\nArray table\n``undefined`` ``nil``\n``null`` ``\"\"`` (an empty string)\nDate string: date's ISO8601 representation, e.g. ``1958-05-21T10:12:00Z``\nRegExp table ``{_jstype='RegExp', caseSensitive=true/false, pattern='my-regexp'}``\nfunction an empty table ``{}`` (don't rely on it)\n============== =================\n\nFunction arguments and return values are passed by value. For example,\nif you modify an argument from inside a JavaScript function then the caller\nLua code won't see the changes, and if you return a global JS object and modify\nit in Lua then object won't be changed in webpage context.\n\n.. note::\n\n The rule of thumb: if an argument or a return value can be serialized\n via JSON, then it is fine.\n\nIf a JavaScript function throws an error, it is re-throwed as a Lua error.\nTo handle errors it is better to use JavaScript try/catch because some of the\ninformation about the error can be lost in JavaScript \u2192 Lua conversion.\n\nSee also: :ref:`splash-runjs`, :ref:`splash-evaljs`, :ref:`splash-wait-for-resume`,\n:ref:`splash-autoload`.", + "short": "Convert JavaScript function to a Lua callable.", + "signature": "lua_func = splash:jsfunc(func)", + "returns": "a function that can be called from Lua to execute JavaScript\ncode in page context.", + "details": "Example:\n\n.. code-block:: lua\n\n function main(splash)\n local get_div_count = splash:jsfunc([[\n function (){\n var body = document.body;\n var divs = body.getElementsByTagName('div');\n return divs.length;\n }\n ]])\n\n splash:go(splash.args.url)\n return get_div_count()\n end\n\nNote how Lua ``[[ ]]`` string syntax is helpful here.\n\nJavaScript functions may accept arguments:\n\n.. code-block:: lua\n\n local vec_len = splash:jsfunc([[\n function(x, y) {\n return Math.sqrt(x*x + y*y)\n }\n ]])\n return {res=vec_len(5, 4)}\n\nGlobal JavaScript functions can be wrapped directly:\n\n.. code-block:: lua\n\n local pow = splash:jsfunc(\"Math.pow\")\n local twenty_five = pow(5, 2) -- 5^2 is 25\n local thousand = pow(10, 3) -- 10^3 is 1000\n\nLua strings, numbers, booleans and tables can be passed as arguments;\nthey are converted to JS strings/numbers/booleans/objects.\nCurrently it is not possible to pass other Lua objects. For example, it\nis not possible to pass a wrapped JavaScript function or a regular Lua function\nas an argument to another wrapped JavaScript function.\n\n.. _lua-js-conversion-rules:\n\nLua \u2192 JavaScript conversion rules:\n\n============== =================\nLua JavaScript\n============== =================\nstring string\nnumber number\nboolean boolean\ntable Object\nnil undefined\n============== =================\n\nFunction result is converted from JavaScript to Lua data type. Only simple\nJS objects are supported. For example, returning a function or a\nJQuery selector from a wrapped function won't work.\n\n.. _js-lua-conversion-rules:\n\nJavaScript \u2192 Lua conversion rules:\n\n============== =================\nJavaScript Lua\n============== =================\nstring string\nnumber number\nboolean boolean\nObject table\nArray table\n``undefined`` ``nil``\n``null`` ``\"\"`` (an empty string)\nDate string: date's ISO8601 representation, e.g. ``1958-05-21T10:12:00Z``\nRegExp table ``{_jstype='RegExp', caseSensitive=true/false, pattern='my-regexp'}``\nfunction an empty table ``{}`` (don't rely on it)\n============== =================\n\nFunction arguments and return values are passed by value. For example,\nif you modify an argument from inside a JavaScript function then the caller\nLua code won't see the changes, and if you return a global JS object and modify\nit in Lua then object won't be changed in webpage context.\n\n.. note::\n\n The rule of thumb: if an argument or a return value can be serialized\n via JSON, then it is fine.\n\nIf a JavaScript function throws an error, it is re-throwed as a Lua error.\nTo handle errors it is better to use JavaScript try/catch because some of the\ninformation about the error can be lost in JavaScript \u2192 Lua conversion.\n\nSee also: :ref:`splash-runjs`, :ref:`splash-evaljs`, :ref:`splash-wait-for-resume`,\n:ref:`splash-autoload`.", + "params": "* func - a string which defines a JavaScript function." + }, + "splash:evaljs": { + "name": "evaljs", + "header": "splash:evaljs", + "content": "Execute a JavaScript snippet in page context and return the result of the\nlast statement.\n\n**Signature:** ``result = splash:evaljs(snippet)``\n\n**Parameters:**\n\n* snippet - a string with JavaScript source code to execute.\n\n**Returns:** the result of the last statement in ``snippet``,\nconverted from JavaScript to Lua data types. In case of syntax errors or\nJavaScript exceptions an error is raised.\n\nJavaScript \u2192 Lua conversion rules are the same as for\n:ref:`splash:jsfunc `.\n\n``splash:evaljs`` is useful for evaluation of short JavaScript snippets\nwithout defining a wrapper function. Example:\n\n.. code-block:: lua\n\n local title = splash:evaljs(\"document.title\")\n\nDon't use :ref:`splash-evaljs` when the result is not needed - it is\ninefficient and could lead to problems; use :ref:`splash-runjs` instead.\nFor example, the following innocent-looking code (using jQuery) may fail:\n\n.. code-block:: lua\n\n splash:evaljs(\"$(console.log('foo'));\")\n\nA gotcha is that to allow chaining jQuery ``$`` function returns a huge object,\n:ref:`splash-evaljs` tries to serialize it and convert to Lua. It is a waste\nof resources, and it could trigger internal protection measures;\n:ref:`splash-runjs` doesn't have this problem.\n\nIf the code you're evaluating needs arguments it is better to use\n:ref:`splash-jsfunc` instead of :ref:`splash-evaljs` and string formatting.\nCompare:\n\n.. code-block:: lua\n\n function main(splash)\n\n local font_size = splash:jsfunc([[\n function(sel) {\n var el = document.querySelector(sel);\n return getComputedStyle(el)[\"font-size\"];\n }\n ]])\n\n local font_size2 = function(sel)\n -- FIXME: escaping of `sel` parameter!\n local js = string.format([[\n var el = document.querySelector(\"%s\");\n getComputedStyle(el)[\"font-size\"]\n ]], sel)\n return splash:evaljs(js)\n end\n\n -- ...\n end\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`,\n:ref:`splash-wait-for-resume`, :ref:`splash-autoload`.", + "short": "Execute a JavaScript snippet in page context and return the result of the\nlast statement.", + "signature": "result = splash:evaljs(snippet)", + "returns": "the result of the last statement in ``snippet``,\nconverted from JavaScript to Lua data types. In case of syntax errors or\nJavaScript exceptions an error is raised.", + "details": "JavaScript \u2192 Lua conversion rules are the same as for\n:ref:`splash:jsfunc `.\n\n``splash:evaljs`` is useful for evaluation of short JavaScript snippets\nwithout defining a wrapper function. Example:\n\n.. code-block:: lua\n\n local title = splash:evaljs(\"document.title\")\n\nDon't use :ref:`splash-evaljs` when the result is not needed - it is\ninefficient and could lead to problems; use :ref:`splash-runjs` instead.\nFor example, the following innocent-looking code (using jQuery) may fail:\n\n.. code-block:: lua\n\n splash:evaljs(\"$(console.log('foo'));\")\n\nA gotcha is that to allow chaining jQuery ``$`` function returns a huge object,\n:ref:`splash-evaljs` tries to serialize it and convert to Lua. It is a waste\nof resources, and it could trigger internal protection measures;\n:ref:`splash-runjs` doesn't have this problem.\n\nIf the code you're evaluating needs arguments it is better to use\n:ref:`splash-jsfunc` instead of :ref:`splash-evaljs` and string formatting.\nCompare:\n\n.. code-block:: lua\n\n function main(splash)\n\n local font_size = splash:jsfunc([[\n function(sel) {\n var el = document.querySelector(sel);\n return getComputedStyle(el)[\"font-size\"];\n }\n ]])\n\n local font_size2 = function(sel)\n -- FIXME: escaping of `sel` parameter!\n local js = string.format([[\n var el = document.querySelector(\"%s\");\n getComputedStyle(el)[\"font-size\"]\n ]], sel)\n return splash:evaljs(js)\n end\n\n -- ...\n end\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`,\n:ref:`splash-wait-for-resume`, :ref:`splash-autoload`.", + "params": "* snippet - a string with JavaScript source code to execute." + }, + "splash:runjs": { + "name": "runjs", + "header": "splash:runjs", + "content": "Run JavaScript code in page context.\n\n**Signature:** ``ok, error = splash:runjs(snippet)``\n\n**Parameters:**\n\n* snippet - a string with JavaScript source code to execute.\n\n**Returns:** ``ok, error`` pair. When the execution is successful\n``ok`` is True. In case of JavaScript errors ``ok`` is ``nil``,\nand ``error`` contains the error string.\n\nExample:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"document.title = 'hello';\"))\n\nNote that JavaScript functions defined using ``function foo(){}`` syntax\n**won't** be added to the global scope:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"function foo(){return 'bar'}\"))\n local res = splash:evaljs(\"foo()\") -- this raises an error\n\nIt is an implementation detail: the code passed to :ref:`splash-runjs`\nis executed in a closure. To define functions use global variables, e.g.:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"foo = function (){return 'bar'}\"))\n local res = splash:evaljs(\"foo()\") -- this returns 'bar'\n\nIf the code needs arguments it is better to use :ref:`splash-jsfunc`.\nCompare:\n\n.. code-block:: lua\n\n function main(splash)\n\n -- Lua function to scroll window to (x, y) position.\n function scroll_to(x, y)\n local js = string.format(\n \"window.scrollTo(%s, %s);\",\n tonumber(x),\n tonumber(y)\n )\n assert(splash:runjs(js))\n end\n\n -- a simpler version using splash:jsfunc\n local scroll_to2 = splash:jsfunc(\"window.scrollTo\")\n\n -- ...\n end\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`, :ref:`splash-autoload`,\n:ref:`splash-wait-for-resume`.", + "short": "Run JavaScript code in page context.", + "signature": "ok, error = splash:runjs(snippet)", + "returns": "``ok, error`` pair. When the execution is successful\n``ok`` is True. In case of JavaScript errors ``ok`` is ``nil``,\nand ``error`` contains the error string.", + "details": "Example:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"document.title = 'hello';\"))\n\nNote that JavaScript functions defined using ``function foo(){}`` syntax\n**won't** be added to the global scope:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"function foo(){return 'bar'}\"))\n local res = splash:evaljs(\"foo()\") -- this raises an error\n\nIt is an implementation detail: the code passed to :ref:`splash-runjs`\nis executed in a closure. To define functions use global variables, e.g.:\n\n.. code-block:: lua\n\n assert(splash:runjs(\"foo = function (){return 'bar'}\"))\n local res = splash:evaljs(\"foo()\") -- this returns 'bar'\n\nIf the code needs arguments it is better to use :ref:`splash-jsfunc`.\nCompare:\n\n.. code-block:: lua\n\n function main(splash)\n\n -- Lua function to scroll window to (x, y) position.\n function scroll_to(x, y)\n local js = string.format(\n \"window.scrollTo(%s, %s);\",\n tonumber(x),\n tonumber(y)\n )\n assert(splash:runjs(js))\n end\n\n -- a simpler version using splash:jsfunc\n local scroll_to2 = splash:jsfunc(\"window.scrollTo\")\n\n -- ...\n end\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`, :ref:`splash-autoload`,\n:ref:`splash-wait-for-resume`.", + "params": "* snippet - a string with JavaScript source code to execute." + }, + "splash:wait_for_resume": { + "name": "wait_for_resume", + "header": "splash:wait_for_resume", + "content": "Run asynchronous JavaScript code in page context. The Lua script will\nyield until the JavaScript code tells it to resume.\n\n**Signature:** ``result, error = splash:wait_for_resume(snippet, timeout)``\n\n**Parameters:**\n\n* snippet - a string with a JavaScript source code to execute. This code\n must include a function called ``main``. The first argument to ``main``\n is an object that has the properties ``resume`` and ``error``. ``resume``\n is a function which can be used to resume Lua execution. It takes an optional\n argument which will be returned to Lua in the ``result.value`` return value.\n ``error`` is a function which can be called with a required string value\n that is returned in the ``error`` return value.\n* timeout - a number which determines (in seconds) how long to allow JavaScript\n to execute before forceably returning control to Lua. Defaults to\n zero, which disables the timeout.\n\n**Returns:** ``result, error`` pair. When the execution is successful\n``result`` is a table. If the value returned by JavaScript is not\n``undefined``, then the ``result`` table will contain a key ``value``\nthat has the value passed to ``splash.resume(\u2026)``. The ``result`` table also\ncontains any additional key/value pairs set by ``splash.set(\u2026)``. In case of\ntimeout or JavaScript errors ``result`` is ``nil`` and ``error`` contains an\nerror message string.\n\nExamples:\n\nThe first, trivial example shows how to transfer control of execution from Lua\nto JavaScript and then back to Lua. This command will tell JavaScript to\nsleep for 3 seconds and then return to Lua. Note that this is an async\noperation: the Lua event loop and the JavaScript event loop continue to run\nduring this 3 second pause, but Lua will not continue executing the current\nfunction until JavaScript calls ``splash.resume()``.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume();\n }, 3000);\n }\n ]])\n\n -- result is {}\n -- error is nil\n\n end\n\n``result`` is set to an empty table to indicate that nothing was returned\nfrom ``splash.resume``. You can use ``assert(splash:wait_for_resume(\u2026))``\neven when JavaScript does not return a value because the empty table signifies\nsuccess to ``assert()``.\n\n.. note::\n\n Your JavaScript code must contain a ``main()`` function. You will get an\n error if you do not include it. The first argument to this function can\n have any name you choose, of course. We will call it ``splash`` by\n convention in this documentation.\n\nThe next example shows how to return a value from JavaScript to Lua.\nYou can return booleans, numbers, strings, arrays, or objects.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume([1, 2, 'red', 'blue']);\n }, 3000);\n }\n ]])\n\n -- result is {value=[1, 2, 'red', 'blue']}\n -- error is nil\n\n end\n\n.. note::\n\n As with :ref:`splash-evaljs`, be wary of returning objects that are\n too large, such as the ``$`` object in jQuery, which will consume a lot\n of time and memory to convert to a Lua result.\n\nYou can also set additional key/value pairs in JavaScript with the\n``splash.set(key, value)`` function. Key/value pairs will be included\nin the ``result`` table returned to Lua. The following example demonstrates\nthis.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.set(\"foo\", \"bar\");\n splash.resume(\"ok\");\n }, 3000);\n }\n ]])\n\n -- result is {foo=\"bar\", value=\"ok\"}\n -- error is nil\n\n end\n\nThe next example shows an incorrect usage of ``splash:wait_for_resume()``:\nthe JavaScript code does not contain a ``main()`` function. ``result`` is\nnil because ``splash.resume()`` is never called, and ``error`` contains\nan error message explaining the mistake.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n console.log('hello!');\n ]])\n\n -- result is nil\n -- error is \"error: wait_for_resume(): no main() function defined\"\n\n end\n\nThe next example shows error handling. If ``splash.error(\u2026)`` is\ncalled instead of ``splash.resume()``, then ``result`` will be ``nil``\nand ``error`` will contain the string passed to ``splash.error(\u2026)``.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.error(\"Goodbye, cruel world!\");\n }, 3000);\n }\n ]])\n\n -- result is nil\n -- error is \"error: Goodbye, cruel world!\"\n\n end\n\nYour JavaScript code must either call ``splash.resume()`` or\n``splash.error()`` exactly one time. Subsequent calls to either function\nhave no effect, as shown in the next example.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume(\"ok\");\n splash.resume(\"still ok\");\n splash.error(\"not ok\");\n }, 3000);\n }\n ]])\n\n -- result is {value=\"ok\"}\n -- error is nil\n\n end\n\nThe next example shows the effect of the ``timeout`` argument. We have set\nthe ``timeout`` argument to 1 second, but our JavaScript code will not call\n``splash.resume()`` for 3 seconds, which guarantees that\n``splash:wait_for_resume()`` will time out.\n\nWhen it times out, ``result`` will be nil, ``error`` will contain a string\nexplaining the timeout, and Lua will continue executing. Calling\n``splash.resume()`` or ``splash.error()`` after a timeout has no effect.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume(\"Hello, world!\");\n }, 3000);\n }\n ]], 1)\n\n -- result is nil\n -- error is \"error: One shot callback timed out while waiting for resume() or error().\"\n\n end\n\n.. note::\n\n The timeout must be >= 0. If the timeout is 0, then\n ``splash:wait_for_resume()`` will never timeout (although Splash's\n HTTP timeout still applies).\n\nNote that your JavaScript code is not forceably canceled by a timeout: it may\ncontinue to run until Splash shuts down the entire browser context.\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`, :ref:`splash-evaljs`.", + "short": "Run asynchronous JavaScript code in page context. The Lua script will\nyield until the JavaScript code tells it to resume.", + "signature": "result, error = splash:wait_for_resume(snippet, timeout)", + "returns": "``result, error`` pair. When the execution is successful\n``result`` is a table. If the value returned by JavaScript is not\n``undefined``, then the ``result`` table will contain a key ``value``\nthat has the value passed to ``splash.resume(\u2026)``. The ``result`` table also\ncontains any additional key/value pairs set by ``splash.set(\u2026)``. In case of\ntimeout or JavaScript errors ``result`` is ``nil`` and ``error`` contains an\nerror message string.", + "details": "Examples:\n\nThe first, trivial example shows how to transfer control of execution from Lua\nto JavaScript and then back to Lua. This command will tell JavaScript to\nsleep for 3 seconds and then return to Lua. Note that this is an async\noperation: the Lua event loop and the JavaScript event loop continue to run\nduring this 3 second pause, but Lua will not continue executing the current\nfunction until JavaScript calls ``splash.resume()``.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume();\n }, 3000);\n }\n ]])\n\n -- result is {}\n -- error is nil\n\n end\n\n``result`` is set to an empty table to indicate that nothing was returned\nfrom ``splash.resume``. You can use ``assert(splash:wait_for_resume(\u2026))``\neven when JavaScript does not return a value because the empty table signifies\nsuccess to ``assert()``.\n\n.. note::\n\n Your JavaScript code must contain a ``main()`` function. You will get an\n error if you do not include it. The first argument to this function can\n have any name you choose, of course. We will call it ``splash`` by\n convention in this documentation.\n\nThe next example shows how to return a value from JavaScript to Lua.\nYou can return booleans, numbers, strings, arrays, or objects.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume([1, 2, 'red', 'blue']);\n }, 3000);\n }\n ]])\n\n -- result is {value=[1, 2, 'red', 'blue']}\n -- error is nil\n\n end\n\n.. note::\n\n As with :ref:`splash-evaljs`, be wary of returning objects that are\n too large, such as the ``$`` object in jQuery, which will consume a lot\n of time and memory to convert to a Lua result.\n\nYou can also set additional key/value pairs in JavaScript with the\n``splash.set(key, value)`` function. Key/value pairs will be included\nin the ``result`` table returned to Lua. The following example demonstrates\nthis.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.set(\"foo\", \"bar\");\n splash.resume(\"ok\");\n }, 3000);\n }\n ]])\n\n -- result is {foo=\"bar\", value=\"ok\"}\n -- error is nil\n\n end\n\nThe next example shows an incorrect usage of ``splash:wait_for_resume()``:\nthe JavaScript code does not contain a ``main()`` function. ``result`` is\nnil because ``splash.resume()`` is never called, and ``error`` contains\nan error message explaining the mistake.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n console.log('hello!');\n ]])\n\n -- result is nil\n -- error is \"error: wait_for_resume(): no main() function defined\"\n\n end\n\nThe next example shows error handling. If ``splash.error(\u2026)`` is\ncalled instead of ``splash.resume()``, then ``result`` will be ``nil``\nand ``error`` will contain the string passed to ``splash.error(\u2026)``.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.error(\"Goodbye, cruel world!\");\n }, 3000);\n }\n ]])\n\n -- result is nil\n -- error is \"error: Goodbye, cruel world!\"\n\n end\n\nYour JavaScript code must either call ``splash.resume()`` or\n``splash.error()`` exactly one time. Subsequent calls to either function\nhave no effect, as shown in the next example.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume(\"ok\");\n splash.resume(\"still ok\");\n splash.error(\"not ok\");\n }, 3000);\n }\n ]])\n\n -- result is {value=\"ok\"}\n -- error is nil\n\n end\n\nThe next example shows the effect of the ``timeout`` argument. We have set\nthe ``timeout`` argument to 1 second, but our JavaScript code will not call\n``splash.resume()`` for 3 seconds, which guarantees that\n``splash:wait_for_resume()`` will time out.\n\nWhen it times out, ``result`` will be nil, ``error`` will contain a string\nexplaining the timeout, and Lua will continue executing. Calling\n``splash.resume()`` or ``splash.error()`` after a timeout has no effect.\n\n.. code-block:: lua\n\n function main(splash)\n\n local result, error = splash:wait_for_resume([[\n function main(splash) {\n setTimeout(function () {\n splash.resume(\"Hello, world!\");\n }, 3000);\n }\n ]], 1)\n\n -- result is nil\n -- error is \"error: One shot callback timed out while waiting for resume() or error().\"\n\n end\n\n.. note::\n\n The timeout must be >= 0. If the timeout is 0, then\n ``splash:wait_for_resume()`` will never timeout (although Splash's\n HTTP timeout still applies).\n\nNote that your JavaScript code is not forceably canceled by a timeout: it may\ncontinue to run until Splash shuts down the entire browser context.\n\nSee also: :ref:`splash-runjs`, :ref:`splash-jsfunc`, :ref:`splash-evaljs`.", + "params": "* snippet - a string with a JavaScript source code to execute. This code\n must include a function called ``main``. The first argument to ``main``\n is an object that has the properties ``resume`` and ``error``. ``resume``\n is a function which can be used to resume Lua execution. It takes an optional\n argument which will be returned to Lua in the ``result.value`` return value.\n ``error`` is a function which can be called with a required string value\n that is returned in the ``error`` return value.\n* timeout - a number which determines (in seconds) how long to allow JavaScript\n to execute before forceably returning control to Lua. Defaults to\n zero, which disables the timeout." + }, + "splash:autoload": { + "name": "autoload", + "header": "splash:autoload", + "content": "Set JavaScript to load automatically on each page load.\n\n**Signature:** ``ok, reason = splash:autoload{source_or_url, source=nil, url=nil}``\n\n**Parameters:**\n\n* source_or_url - either a string with JavaScript source code or an URL\n to load the JavaScript code from;\n* source - a string with JavaScript source code;\n* url - an URL to load JavaScript source code from.\n\n**Returns:** ``ok, reason`` pair. If ``ok`` is nil, error happened and\n``reason`` contains an error description.\n\n:ref:`splash-autoload` allows to execute JavaScript code at each page load.\n:ref:`splash-autoload` doesn't doesn't execute the passed\nJavaScript code itself. To execute some code once, *after* page is loaded\nuse :ref:`splash-runjs` or :ref:`splash-jsfunc`.\n\n:ref:`splash-autoload` can be used to preload utility JavaScript libraries\nor replace JavaScript objects before a webpage has a chance to do it.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:autoload([[\n function get_document_title(){\n return document.title;\n }\n ]])\n assert(splash:go(splash.args.url))\n return splash:evaljs(\"get_document_title()\")\n end\n\nFor the convenience, when a first :ref:`splash-autoload` argument starts\nwith \"http://\" or \"https://\" a script from the passed URL is loaded.\nExample 2 - make sure a remote library is available:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:autoload(\"https://code.jquery.com/jquery-2.1.3.min.js\"))\n assert(splash:go(splash.args.url))\n return splash:evaljs(\"$.fn.jquery\") -- return jQuery version\n end\n\nTo disable URL auto-detection use 'source' and 'url' arguments:\n\n.. code-block:: lua\n\n splash:autoload{url=\"https://code.jquery.com/jquery-2.1.3.min.js\"}\n splash:autoload{source=\"window.foo = 'bar';\"}\n\nIt is a good practice not to rely on auto-detection when the argument\nis not a constant.\n\nIf :ref:`splash-autoload` is called multiple times then all its scripts\nare executed on page load, in order they were added.\n\nSee also: :ref:`splash-evaljs`, :ref:`splash-runjs`, :ref:`splash-jsfunc`,\n:ref:`splash-wait-for-resume`.", + "short": "Set JavaScript to load automatically on each page load.", + "signature": "ok, reason = splash:autoload{source_or_url, source=nil, url=nil}", + "returns": "``ok, reason`` pair. If ``ok`` is nil, error happened and\n``reason`` contains an error description.", + "details": ":ref:`splash-autoload` allows to execute JavaScript code at each page load.\n:ref:`splash-autoload` doesn't doesn't execute the passed\nJavaScript code itself. To execute some code once, *after* page is loaded\nuse :ref:`splash-runjs` or :ref:`splash-jsfunc`.\n\n:ref:`splash-autoload` can be used to preload utility JavaScript libraries\nor replace JavaScript objects before a webpage has a chance to do it.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:autoload([[\n function get_document_title(){\n return document.title;\n }\n ]])\n assert(splash:go(splash.args.url))\n return splash:evaljs(\"get_document_title()\")\n end\n\nFor the convenience, when a first :ref:`splash-autoload` argument starts\nwith \"http://\" or \"https://\" a script from the passed URL is loaded.\nExample 2 - make sure a remote library is available:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:autoload(\"https://code.jquery.com/jquery-2.1.3.min.js\"))\n assert(splash:go(splash.args.url))\n return splash:evaljs(\"$.fn.jquery\") -- return jQuery version\n end\n\nTo disable URL auto-detection use 'source' and 'url' arguments:\n\n.. code-block:: lua\n\n splash:autoload{url=\"https://code.jquery.com/jquery-2.1.3.min.js\"}\n splash:autoload{source=\"window.foo = 'bar';\"}\n\nIt is a good practice not to rely on auto-detection when the argument\nis not a constant.\n\nIf :ref:`splash-autoload` is called multiple times then all its scripts\nare executed on page load, in order they were added.\n\nSee also: :ref:`splash-evaljs`, :ref:`splash-runjs`, :ref:`splash-jsfunc`,\n:ref:`splash-wait-for-resume`.", + "params": "* source_or_url - either a string with JavaScript source code or an URL\n to load the JavaScript code from;\n* source - a string with JavaScript source code;\n* url - an URL to load JavaScript source code from." + }, + "splash:http_get": { + "name": "http_get", + "header": "splash:http_get", + "content": "Send an HTTP request and return a response without loading\nthe result to the browser window.\n\n**Signature:** ``response = splash:http_get{url, headers=nil, follow_redirects=true}``\n\n**Parameters:**\n\n* url - URL to load;\n* headers - a Lua table with HTTP headers to add/replace in the initial request;\n* follow_redirects - whether to follow HTTP redirects.\n\n**Returns:** a Lua table with the response in `HAR response`_ format.\n\nExample:\n\n.. code-block:: lua\n\n local reply = splash:http_get(\"http://example.com\")\n -- reply.content.text contains raw HTML data\n -- reply.status contains HTTP status code, as a number\n -- see HAR docs for more info\n\nIn addition to all HAR fields the response contains \"ok\" flag which is true\nfor successful responses and false when error happened:\n\n.. code-block:: lua\n\n local reply = splash:http_get(\"some-bad-url\")\n -- reply.ok == false\n\nThis method doesn't change the current page contents and URL.\nTo load a webpage to the browser use :ref:`splash-go`.\n\n.. _HAR response: http://www.softwareishard.com/blog/har-12-spec/#response", + "short": "Send an HTTP request and return a response without loading\nthe result to the browser window.", + "signature": "response = splash:http_get{url, headers=nil, follow_redirects=true}", + "returns": "a Lua table with the response in `HAR response`_ format.", + "details": "Example:\n\n.. code-block:: lua\n\n local reply = splash:http_get(\"http://example.com\")\n -- reply.content.text contains raw HTML data\n -- reply.status contains HTTP status code, as a number\n -- see HAR docs for more info\n\nIn addition to all HAR fields the response contains \"ok\" flag which is true\nfor successful responses and false when error happened:\n\n.. code-block:: lua\n\n local reply = splash:http_get(\"some-bad-url\")\n -- reply.ok == false\n\nThis method doesn't change the current page contents and URL.\nTo load a webpage to the browser use :ref:`splash-go`.\n\n.. _HAR response: http://www.softwareishard.com/blog/har-12-spec/#response", + "params": "* url - URL to load;\n* headers - a Lua table with HTTP headers to add/replace in the initial request;\n* follow_redirects - whether to follow HTTP redirects." + }, + "splash:set_content": { + "name": "set_content", + "header": "splash:set_content", + "content": "Set the content of the current page and wait until the page loads.\n\n**Signature:** ``ok, reason = splash:set_content{data, mime_type=\"text/html; charset=utf-8\", baseurl=\"\"}``\n\n**Parameters:**\n\n* data - new page content;\n* mime_type - MIME type of the content;\n* baseurl - external objects referenced in the content are located\n relative to baseurl.\n\n**Returns:** ``ok, reason`` pair. If ``ok`` is nil then error happened during\npage load; ``reason`` provides an information about error type.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:set_content(\"

hello

\"))\n return splash:png()\n end", + "short": "Set the content of the current page and wait until the page loads.", + "signature": "ok, reason = splash:set_content{data, mime_type=\"text/html; charset=utf-8\", baseurl=\"\"}", + "returns": "``ok, reason`` pair. If ``ok`` is nil then error happened during\npage load; ``reason`` provides an information about error type.", + "details": "Example:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:set_content(\"

hello

\"))\n return splash:png()\n end", + "params": "* data - new page content;\n* mime_type - MIME type of the content;\n* baseurl - external objects referenced in the content are located\n relative to baseurl." + }, + "splash:html": { + "name": "html", + "header": "splash:html", + "content": "Return a HTML snapshot of a current page (as a string).\n\n**Signature:** ``html = splash:html()``\n\n**Returns:** contents of a current page (as a string).\n\nExample:\n\n.. code-block:: lua\n\n -- A simplistic implementation of render.html endpoint\n function main(splash)\n splash:set_result_content_type(\"text/html; charset=utf-8\")\n assert(splash:go(splash.args.url))\n return splash:html()\n end\n\nNothing prevents us from taking multiple HTML snapshots. For example, let's\nvisit first 10 pages on a website, and for each page store\ninitial HTML snapshot and an HTML snapshot after waiting 0.5s:\n\n.. code-block:: lua\n\n -- Given an url, this function returns a table with\n -- two HTML snapshots: HTML right after page is loaded,\n -- and HTML after waiting 0.5s.\n function page_info(splash, url)\n local ok, msg = splash:go(url)\n if not ok then\n return {ok=false, reason=msg}\n end\n local res = {before=splash:html()}\n assert(splash:wait(0.5)) -- this shouldn't fail, so we wrap it in assert\n res.after = splash:html() -- the same as res[\"after\"] = splash:html()\n res.ok = true\n return res\n end\n\n -- visit first 10 http://example.com/pages/ pages,\n -- return their html snapshots\n function main(splash)\n local result = {}\n for i=1,10 do\n local url = \"http://example.com/pages/\" .. page_num\n result[i] = page_info(splash, url)\n end\n return result\n end", + "short": "Return a HTML snapshot of a current page (as a string).", + "signature": "html = splash:html()", + "returns": "contents of a current page (as a string).", + "details": "Example:\n\n.. code-block:: lua\n\n -- A simplistic implementation of render.html endpoint\n function main(splash)\n splash:set_result_content_type(\"text/html; charset=utf-8\")\n assert(splash:go(splash.args.url))\n return splash:html()\n end\n\nNothing prevents us from taking multiple HTML snapshots. For example, let's\nvisit first 10 pages on a website, and for each page store\ninitial HTML snapshot and an HTML snapshot after waiting 0.5s:\n\n.. code-block:: lua\n\n -- Given an url, this function returns a table with\n -- two HTML snapshots: HTML right after page is loaded,\n -- and HTML after waiting 0.5s.\n function page_info(splash, url)\n local ok, msg = splash:go(url)\n if not ok then\n return {ok=false, reason=msg}\n end\n local res = {before=splash:html()}\n assert(splash:wait(0.5)) -- this shouldn't fail, so we wrap it in assert\n res.after = splash:html() -- the same as res[\"after\"] = splash:html()\n res.ok = true\n return res\n end\n\n -- visit first 10 http://example.com/pages/ pages,\n -- return their html snapshots\n function main(splash)\n local result = {}\n for i=1,10 do\n local url = \"http://example.com/pages/\" .. page_num\n result[i] = page_info(splash, url)\n end\n return result\n end", + "params": null + }, + "splash:png": { + "name": "png", + "header": "splash:png", + "content": "Return a `width x height` screenshot of a current page in PNG format.\n\n**Signature:** ``png = splash:png{width=nil, height=nil, render_all=false, scale_method='raster'}``\n\n**Parameters:**\n\n* width - optional, width of a screenshot in pixels;\n* height - optional, height of a screenshot in pixels;\n* render_all - optional, if ``true`` render the whole webpage;\n* scale_method - optional, method to use when resizing the image, ``'raster'``\n or ``'vector'``\n\n**Returns:** PNG screenshot data.\n\nWithout arguments ``splash:png()`` will take a snapshot of the current viewport.\n\n*width* parameter sets the width of the resulting image. If the viewport has a\ndifferent width, the image is scaled up or down to match the specified one.\nFor example, if the viewport is 1024px wide then ``splash:png{width=100}`` will\nreturn a screenshot of the whole viewport, but the image will be downscaled to\n100px width.\n\n*height* parameter sets the height of the resulting image. If the viewport has\na different height, the image is trimmed or extended vertically to match the\nspecified one without resizing the content. The region created by such\nextension is transparent.\n\nTo set the viewport size use :ref:`splash-set-viewport-size`,\n:ref:`splash-set-viewport-full` or *render_all* argument. ``render_all=true``\nis equivalent to running ``splash:set_viewport_full()`` just before the\nrendering and restoring the viewport size afterwards.\n\n*scale_method* parameter must be either ``'raster'`` or ``'vector'``. When\n``scale_method='raster'``, the image is resized per-pixel. When\n``scale_method='vector'``, the image is resized per-element during rendering.\nVector scaling is more performant and produces sharper images, however it may\ncause rendering artifacts, so use it with caution.\n\nIf the result of ``splash:png()`` is returned directly as a result of\n\"main\" function, the screenshot is returned as binary data:\n\n.. code-block:: lua\n\n -- A simplistic implementation of render.png endpoint\n function main(splash)\n splash:set_result_content_type(\"image/png\")\n assert(splash:go(splash.args.url))\n return splash:png{\n width=splash.args.width,\n height=splash.args.height\n }\n end\n\nIf the result of ``splash:png()`` is returned as a table value, it is encoded\nto base64 to make it possible to embed in JSON and build a data:uri\non a client (magic!):\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n return {png=splash:png()}\n end\n\nIf your script returns the result of ``splash:png()`` in a top-level\n``\"png\"`` key (as we've done in a previous example) then Splash UI\nwill display it as an image.", + "short": "Return a `width x height` screenshot of a current page in PNG format.", + "signature": "png = splash:png{width=nil, height=nil, render_all=false, scale_method='raster'}", + "returns": "PNG screenshot data.", + "details": "Without arguments ``splash:png()`` will take a snapshot of the current viewport.\n\n*width* parameter sets the width of the resulting image. If the viewport has a\ndifferent width, the image is scaled up or down to match the specified one.\nFor example, if the viewport is 1024px wide then ``splash:png{width=100}`` will\nreturn a screenshot of the whole viewport, but the image will be downscaled to\n100px width.\n\n*height* parameter sets the height of the resulting image. If the viewport has\na different height, the image is trimmed or extended vertically to match the\nspecified one without resizing the content. The region created by such\nextension is transparent.\n\nTo set the viewport size use :ref:`splash-set-viewport-size`,\n:ref:`splash-set-viewport-full` or *render_all* argument. ``render_all=true``\nis equivalent to running ``splash:set_viewport_full()`` just before the\nrendering and restoring the viewport size afterwards.\n\n*scale_method* parameter must be either ``'raster'`` or ``'vector'``. When\n``scale_method='raster'``, the image is resized per-pixel. When\n``scale_method='vector'``, the image is resized per-element during rendering.\nVector scaling is more performant and produces sharper images, however it may\ncause rendering artifacts, so use it with caution.\n\nIf the result of ``splash:png()`` is returned directly as a result of\n\"main\" function, the screenshot is returned as binary data:\n\n.. code-block:: lua\n\n -- A simplistic implementation of render.png endpoint\n function main(splash)\n splash:set_result_content_type(\"image/png\")\n assert(splash:go(splash.args.url))\n return splash:png{\n width=splash.args.width,\n height=splash.args.height\n }\n end\n\nIf the result of ``splash:png()`` is returned as a table value, it is encoded\nto base64 to make it possible to embed in JSON and build a data:uri\non a client (magic!):\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n return {png=splash:png()}\n end\n\nIf your script returns the result of ``splash:png()`` in a top-level\n``\"png\"`` key (as we've done in a previous example) then Splash UI\nwill display it as an image.", + "params": "* width - optional, width of a screenshot in pixels;\n* height - optional, height of a screenshot in pixels;\n* render_all - optional, if ``true`` render the whole webpage;\n* scale_method - optional, method to use when resizing the image, ``'raster'``\n or ``'vector'``" + }, + "splash:har": { + "name": "har", + "header": "splash:har", + "content": "**Signature:** ``har = splash:har()``\n\n**Returns:** information about pages loaded, events happened,\nnetwork requests sent and responses received in HAR_ format.\n\nIf your script returns the result of ``splash:har()`` in a top-level\n``\"har\"`` key then Splash UI will give you a nice diagram with network\ninformation (similar to \"Network\" tabs in Firefox or Chrome developer tools):\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n return {har=splash:har()}\n end\n\n.. _HAR: http://www.softwareishard.com/blog/har-12-spec/", + "short": "", + "signature": "har = splash:har()", + "returns": "information about pages loaded, events happened,\nnetwork requests sent and responses received in HAR_ format.", + "details": "If your script returns the result of ``splash:har()`` in a top-level\n``\"har\"`` key then Splash UI will give you a nice diagram with network\ninformation (similar to \"Network\" tabs in Firefox or Chrome developer tools):\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n return {har=splash:har()}\n end\n\n.. _HAR: http://www.softwareishard.com/blog/har-12-spec/", + "params": null + }, + "splash:history": { + "name": "history", + "header": "splash:history", + "content": "**Signature:** ``entries = splash:history()``\n\n**Returns:** information about requests/responses for the pages loaded, in\n`HAR entries`_ format.\n\n``splash:history`` doesn't return information about related resources\nlike images, scripts, stylesheets or AJAX requests. If you need this\ninformation use :ref:`splash-har`.\n\nLet's get a JSON array with HTTP headers of the response we're displaying:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n local entries = splash:history()\n -- #entries means \"entries length\"; arrays in Lua start from 1\n local last_entry = entries[#entries]\n return {\n headers = last_entry.response.headers\n }\n end\n\n.. _HAR entries: http://www.softwareishard.com/blog/har-12-spec/#entries", + "short": "", + "signature": "entries = splash:history()", + "returns": "information about requests/responses for the pages loaded, in\n`HAR entries`_ format.", + "details": "``splash:history`` doesn't return information about related resources\nlike images, scripts, stylesheets or AJAX requests. If you need this\ninformation use :ref:`splash-har`.\n\nLet's get a JSON array with HTTP headers of the response we're displaying:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(splash.args.url))\n local entries = splash:history()\n -- #entries means \"entries length\"; arrays in Lua start from 1\n local last_entry = entries[#entries]\n return {\n headers = last_entry.response.headers\n }\n end\n\n.. _HAR entries: http://www.softwareishard.com/blog/har-12-spec/#entries", + "params": null + }, + "splash:url": { + "name": "url", + "header": "splash:url", + "content": "**Signature:** ``url = splash:url()``\n\n**Returns:** the current URL.", + "short": "", + "signature": "url = splash:url()", + "returns": "the current URL.", + "details": "**Returns:** the current URL.", + "params": null + }, + "splash:get_cookies": { + "name": "get_cookies", + "header": "splash:get_cookies", + "content": "**Signature:** ``cookies = splash:get_cookies()``\n\n**Returns:** CookieJar contents - an array with all cookies available\nfor the script. The result is returned in `HAR cookies`_ format.\n\n.. _HAR cookies: http://www.softwareishard.com/blog/har-12-spec/#cookies\n\nExample result::\n\n [\n {\n \"name\": \"TestCookie\",\n \"value\": \"Cookie Value\",\n \"path\": \"/\",\n \"domain\": \"www.example.com\",\n \"expires\": \"2016-07-24T19:20:30+02:00\",\n \"httpOnly\": false,\n \"secure\": false,\n }\n ]", + "short": "", + "signature": "cookies = splash:get_cookies()", + "returns": "CookieJar contents - an array with all cookies available\nfor the script. The result is returned in `HAR cookies`_ format.", + "details": ".. _HAR cookies: http://www.softwareishard.com/blog/har-12-spec/#cookies\n\nExample result::\n\n [\n {\n \"name\": \"TestCookie\",\n \"value\": \"Cookie Value\",\n \"path\": \"/\",\n \"domain\": \"www.example.com\",\n \"expires\": \"2016-07-24T19:20:30+02:00\",\n \"httpOnly\": false,\n \"secure\": false,\n }\n ]", + "params": null + }, + "splash:add_cookie": { + "name": "add_cookie", + "header": "splash:add_cookie", + "content": "Add a cookie.\n\n**Signature:** ``cookies = splash:add_cookie{name, value, path=nil, domain=nil, expires=nil, httpOnly=nil, secure=nil}``\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:add_cookie{\"sessionid\", \"237465ghgfsd\", \"/\", domain=\"http://example.com\"}\n splash:go(\"http://example.com/\")\n return splash:html()\n end", + "short": "Add a cookie.", + "signature": "cookies = splash:add_cookie{name, value, path=nil, domain=nil, expires=nil, httpOnly=nil, secure=nil}", + "returns": null, + "details": "Example:\n\n.. code-block:: lua\n\n function main(splash)\n splash:add_cookie{\"sessionid\", \"237465ghgfsd\", \"/\", domain=\"http://example.com\"}\n splash:go(\"http://example.com/\")\n return splash:html()\n end", + "params": null + }, + "splash:init_cookies": { + "name": "init_cookies", + "header": "splash:init_cookies", + "content": "Replace all current cookies with the passed ``cookies``.\n\n**Signature:** ``splash:init_cookies(cookies)``\n\n**Parameters:**\n\n* cookies - a Lua table with all cookies to set, in the same format as\n :ref:`splash-get-cookies` returns.\n\n**Returns:** nil.\n\nExample 1 - save and restore cookies:\n\n.. code-block:: lua\n\n local cookies = splash:get_cookies()\n -- ... do something ...\n splash:init_cookies(cookies) -- restore cookies\n\nExample 2 - initialize cookies manually:\n\n.. code-block:: lua\n\n splash:init_cookies({\n {name=\"baz\", value=\"egg\"},\n {name=\"spam\", value=\"egg\", domain=\"example.com\"},\n {\n name=\"foo\",\n value=\"bar\",\n path=\"/\",\n domain=\"localhost\",\n expires=\"2016-07-24T19:20:30+02:00\",\n secure=true,\n httpOnly=true,\n }\n })\n\n -- do something\n assert(splash:go(\"http://example.com\"))", + "short": "Replace all current cookies with the passed ``cookies``.", + "signature": "splash:init_cookies(cookies)", + "returns": "nil.", + "details": "Example 1 - save and restore cookies:\n\n.. code-block:: lua\n\n local cookies = splash:get_cookies()\n -- ... do something ...\n splash:init_cookies(cookies) -- restore cookies\n\nExample 2 - initialize cookies manually:\n\n.. code-block:: lua\n\n splash:init_cookies({\n {name=\"baz\", value=\"egg\"},\n {name=\"spam\", value=\"egg\", domain=\"example.com\"},\n {\n name=\"foo\",\n value=\"bar\",\n path=\"/\",\n domain=\"localhost\",\n expires=\"2016-07-24T19:20:30+02:00\",\n secure=true,\n httpOnly=true,\n }\n })\n\n -- do something\n assert(splash:go(\"http://example.com\"))", + "params": "* cookies - a Lua table with all cookies to set, in the same format as\n :ref:`splash-get-cookies` returns." + }, + "splash:clear_cookies": { + "name": "clear_cookies", + "header": "splash:clear_cookies", + "content": "Clear all cookies.\n\n**Signature:** ``n_removed = splash:clear_cookies()``\n\n**Returns:** a number of cookies deleted.\n\nTo delete only specific cookies\nuse :ref:`splash-delete-cookies`.", + "short": "Clear all cookies.", + "signature": "n_removed = splash:clear_cookies()", + "returns": "a number of cookies deleted.", + "details": "To delete only specific cookies\nuse :ref:`splash-delete-cookies`.", + "params": null + }, + "splash:delete_cookies": { + "name": "delete_cookies", + "header": "splash:delete_cookies", + "content": "Delete matching cookies.\n\n**Signature:** ``n_removed = splash:delete_cookies{name=nil, url=nil}``\n\n**Parameters:**\n\n* name - a string, optional. All cookies with this name will be deleted.\n* url - a string, optional. Only cookies that should be sent to this url\n will be deleted.\n\n**Returns:** a number of cookies deleted.\n\nThis function does nothing when both *name* and *url* are nil.\nTo remove all cookies use :ref:`splash-clear-cookies` method.", + "short": "Delete matching cookies.", + "signature": "n_removed = splash:delete_cookies{name=nil, url=nil}", + "returns": "a number of cookies deleted.", + "details": "This function does nothing when both *name* and *url* are nil.\nTo remove all cookies use :ref:`splash-clear-cookies` method.", + "params": "* name - a string, optional. All cookies with this name will be deleted.\n* url - a string, optional. Only cookies that should be sent to this url\n will be deleted." + }, + "splash:lock_navigation": { + "name": "lock_navigation", + "header": "splash:lock_navigation", + "content": "Lock navigation.\n\n**Signature:** ``splash:lock_navigation()``\n\nAfter calling this method the navigation away from the current page is no\nlonger permitted - the page is locked to the current URL.", + "short": "Lock navigation.", + "signature": "splash:lock_navigation()", + "returns": null, + "details": "After calling this method the navigation away from the current page is no\nlonger permitted - the page is locked to the current URL.", + "params": null + }, + "splash:unlock_navigation": { + "name": "unlock_navigation", + "header": "splash:unlock_navigation", + "content": "Unlock navigation.\n\n**Signature:** ``splash:unlock_navigation()``\n\nAfter calling this method the navigation away from the page becomes\npermitted. Note that the pending navigation requests suppressed\nby :ref:`splash-lock-navigation` won't be reissued.", + "short": "Unlock navigation.", + "signature": "splash:unlock_navigation()", + "returns": null, + "details": "After calling this method the navigation away from the page becomes\npermitted. Note that the pending navigation requests suppressed\nby :ref:`splash-lock-navigation` won't be reissued.", + "params": null + }, + "splash:set_result_content_type": { + "name": "set_result_content_type", + "header": "splash:set_result_content_type", + "content": "Set Content-Type of a result returned to a client.\n\n**Signature:** ``splash:set_result_content_type(content_type)``\n\n**Parameters:**\n\n* content_type - a string with Content-Type header value.\n\n**Returns:** nil.\n\nIf a table is returned by \"main\" function then\n``splash:set_result_content_type`` has no effect: Content-Type of the result\nis set to ``application/json``.\n\nThis function **does not** set Content-Type header for requests\ninitiated by :ref:`splash-go`; this function is for setting Content-Type\nheader of a result.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_result_content_type(\"text/xml\")\n return [[\n \n \n Tove\n Jani\n Reminder\n Don't forget me this weekend!\n \n ]]\n end", + "short": "Set Content-Type of a result returned to a client.", + "signature": "splash:set_result_content_type(content_type)", + "returns": "nil.", + "details": "If a table is returned by \"main\" function then\n``splash:set_result_content_type`` has no effect: Content-Type of the result\nis set to ``application/json``.\n\nThis function **does not** set Content-Type header for requests\ninitiated by :ref:`splash-go`; this function is for setting Content-Type\nheader of a result.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_result_content_type(\"text/xml\")\n return [[\n \n \n Tove\n Jani\n Reminder\n Don't forget me this weekend!\n \n ]]\n end", + "params": "* content_type - a string with Content-Type header value." + }, + "splash:set_images_enabled": { + "name": "set_images_enabled", + "header": "splash:set_images_enabled", + "content": "Enable/disable images.\n\n**Signature:** ``splash:set_images_enabled(enabled)``\n\n**Parameters:**\n\n* enabled - ``true`` to enable images, ``false`` to disable them.\n\n**Returns:** nil.\n\nBy default, images are enabled. Disabling of the images can save a lot\nof network traffic (usually around ~50%) and make rendering faster.\nNote that this option can affect the JavaScript code inside page:\ndisabling of the images may change sizes and positions of DOM elements,\nand scripts may read and use them.\n\nSplash uses in-memory cache; cached images will be displayed\neven when images are disabled. So if you load a page, then disable images,\nthen load a new page, then likely first page will display all images\nand second page will display some images (the ones common with the first page).\nSplash cache is shared between scripts executed in the same process, so you\ncan see some images even if they are disabled at the beginning of the script.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_images_enabled(false)\n assert(splash:go(\"http://example.com\"))\n return {png=splash:png()}\n end", + "short": "Enable/disable images.", + "signature": "splash:set_images_enabled(enabled)", + "returns": "nil.", + "details": "By default, images are enabled. Disabling of the images can save a lot\nof network traffic (usually around ~50%) and make rendering faster.\nNote that this option can affect the JavaScript code inside page:\ndisabling of the images may change sizes and positions of DOM elements,\nand scripts may read and use them.\n\nSplash uses in-memory cache; cached images will be displayed\neven when images are disabled. So if you load a page, then disable images,\nthen load a new page, then likely first page will display all images\nand second page will display some images (the ones common with the first page).\nSplash cache is shared between scripts executed in the same process, so you\ncan see some images even if they are disabled at the beginning of the script.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_images_enabled(false)\n assert(splash:go(\"http://example.com\"))\n return {png=splash:png()}\n end", + "params": "* enabled - ``true`` to enable images, ``false`` to disable them." + }, + "splash:get_viewport_size": { + "name": "get_viewport_size", + "header": "splash:get_viewport_size", + "content": "Get the browser viewport size.\n\n**Signature:** ``width, height = splash:get_viewport_size()``\n\n**Returns:** two numbers: width and height of the viewport in pixels.", + "short": "Get the browser viewport size.", + "signature": "width, height = splash:get_viewport_size()", + "returns": "two numbers: width and height of the viewport in pixels.", + "details": "", + "params": null + }, + "splash:set_viewport_size": { + "name": "set_viewport_size", + "header": "splash:set_viewport_size", + "content": "Set the browser viewport size.\n\n**Signature:** ``splash:set_viewport_size(width, height)``\n\n**Parameters:**\n\n* width - integer, requested viewport width in pixels;\n* height - integer, requested viewport height in pixels.\n\n**Returns:** nil.\n\nThis will change the size of the visible area and subsequent rendering\ncommands, e.g., :ref:`splash-png`, will produce an image with the specified\nsize.\n\n:ref:`splash-png` uses the viewport size.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_viewport_size(1980, 1020)\n assert(splash:go(\"http://example.com\"))\n return {png=splash:png()}\n end\n\n.. note::\n\n This will relayout all document elements and affect geometry variables, such\n as ``window.innerWidth`` and ``window.innerHeight``. However\n ``window.onresize`` event callback will only be invoked during the next\n asynchronous operation and :ref:`splash-png` is notably synchronous, so if\n you have resized a page and want it to react accordingly before taking the\n screenshot, use :ref:`splash-wait`.", + "short": "Set the browser viewport size.", + "signature": "splash:set_viewport_size(width, height)", + "returns": "nil.", + "details": "This will change the size of the visible area and subsequent rendering\ncommands, e.g., :ref:`splash-png`, will produce an image with the specified\nsize.\n\n:ref:`splash-png` uses the viewport size.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n splash:set_viewport_size(1980, 1020)\n assert(splash:go(\"http://example.com\"))\n return {png=splash:png()}\n end\n\n.. note::\n\n This will relayout all document elements and affect geometry variables, such\n as ``window.innerWidth`` and ``window.innerHeight``. However\n ``window.onresize`` event callback will only be invoked during the next\n asynchronous operation and :ref:`splash-png` is notably synchronous, so if\n you have resized a page and want it to react accordingly before taking the\n screenshot, use :ref:`splash-wait`.", + "params": "* width - integer, requested viewport width in pixels;\n* height - integer, requested viewport height in pixels." + }, + "splash:set_viewport_full": { + "name": "set_viewport_full", + "header": "splash:set_viewport_full", + "content": "Resize browser viewport to fit the whole page.\n\n**Signature:** ``width, height = splash:set_viewport_full()``\n\n**Returns:** two numbers: width and height the viewport is set to, in pixels.\n\n``splash:set_viewport_full`` should be called only after page is loaded, and\nsome time passed after that (use :ref:`splash-wait`). This is an unfortunate\nrestriction, but it seems that this is the only way to make automatic resizing\nwork reliably.\n\nSee :ref:`splash-set-viewport-size` for a note about interaction with JS.\n\n:ref:`splash-png` uses the viewport size.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(\"http://example.com\"))\n assert(splash:wait(0.5))\n splash:set_viewport_full()\n return {png=splash:png()}\n end", + "short": "Resize browser viewport to fit the whole page.", + "signature": "width, height = splash:set_viewport_full()", + "returns": "two numbers: width and height the viewport is set to, in pixels.", + "details": "``splash:set_viewport_full`` should be called only after page is loaded, and\nsome time passed after that (use :ref:`splash-wait`). This is an unfortunate\nrestriction, but it seems that this is the only way to make automatic resizing\nwork reliably.\n\nSee :ref:`splash-set-viewport-size` for a note about interaction with JS.\n\n:ref:`splash-png` uses the viewport size.\n\nExample:\n\n.. code-block:: lua\n\n function main(splash)\n assert(splash:go(\"http://example.com\"))\n assert(splash:wait(0.5))\n splash:set_viewport_full()\n return {png=splash:png()}\n end", + "params": null + }, + "splash:set_user_agent": { + "name": "set_user_agent", + "header": "splash:set_user_agent", + "content": "Overwrite the User-Agent header for all further requests.\n\n**Signature:** ``splash:set_user_agent(value)``\n\n**Parameters:**\n\n* value - string, a value of User-Agent HTTP header.\n\n**Returns:** nil.", + "short": "Overwrite the User-Agent header for all further requests.", + "signature": "splash:set_user_agent(value)", + "returns": "nil.", + "details": "**Returns:** nil.", + "params": "* value - string, a value of User-Agent HTTP header." + }, + "splash:set_custom_headers": { + "name": "set_custom_headers", + "header": "splash:set_custom_headers", + "content": "Set custom HTTP headers to send with each request.\n\n**Signature:** ``splash:set_custom_headers(headers)``\n\n**Parameters:**\n\n* headers - a Lua table with HTTP headers.\n\n**Returns:** nil.\n\nHeaders are merged with WebKit default headers, overwriting WebKit values\nin case of conflicts.\n\nWhen ``headers`` argument of :ref:`splash-go` is used headers set with\n``splash:set_custom_headers`` are not applied to the initial request:\nvalues are not merged, ``headers`` argument of :ref:`splash-go` has\nhigher priority.\n\nExample:\n\n.. code-block:: lua\n\n splash:set_custom_headers({\n [\"Header-1\"] = \"Value 1\",\n [\"Header-2\"] = \"Value 2\",\n })\n\nNamed arguments are not supported for this function.", + "short": "Set custom HTTP headers to send with each request.", + "signature": "splash:set_custom_headers(headers)", + "returns": "nil.", + "details": "Headers are merged with WebKit default headers, overwriting WebKit values\nin case of conflicts.\n\nWhen ``headers`` argument of :ref:`splash-go` is used headers set with\n``splash:set_custom_headers`` are not applied to the initial request:\nvalues are not merged, ``headers`` argument of :ref:`splash-go` has\nhigher priority.\n\nExample:\n\n.. code-block:: lua\n\n splash:set_custom_headers({\n [\"Header-1\"] = \"Value 1\",\n [\"Header-2\"] = \"Value 2\",\n })\n\nNamed arguments are not supported for this function.", + "params": "* headers - a Lua table with HTTP headers." + }, + "splash:get_perf_stats": { + "name": "get_perf_stats", + "header": "splash:get_perf_stats", + "content": "Return performance-related statistics.\n\n**Signature:** ``stats = splash:get_perf_stats()``\n\n**Returns:** a table that can be useful for performance analysis.\n\nAs of now, this table contains:\n\n* ``walltime`` - (float) number of seconds since epoch, analog of ``os.clock``\n* ``cputime`` - (float) number of cpu seconds consumed by splash process\n* ``maxrss`` - (int) high water mark number of bytes of RAM consumed by splash\n process", + "short": "Return performance-related statistics.", + "signature": "stats = splash:get_perf_stats()", + "returns": "a table that can be useful for performance analysis.", + "details": "As of now, this table contains:\n\n* ``walltime`` - (float) number of seconds since epoch, analog of ``os.clock``\n* ``cputime`` - (float) number of cpu seconds consumed by splash process\n* ``maxrss`` - (int) high water mark number of bytes of RAM consumed by splash\n process", + "params": null + }, + "splash.args": { + "name": null, + "header": "splash.args", + "content": "``splash.args`` is a table with incoming parameters. It contains\nmerged values from the orignal URL string (GET arguments) and\nvalues sent using ``application/json`` POST request.", + "short": null, + "signature": null, + "returns": null, + "details": null, + "params": null + } +} \ No newline at end of file diff --git a/splash/kernel/kernel.py b/splash/kernel/kernel.py index d92ce9800..ab4295906 100644 --- a/splash/kernel/kernel.py +++ b/splash/kernel/kernel.py @@ -19,6 +19,7 @@ from splash.kernel.kernelbase import Kernel from splash.utils import BinaryCapsule from splash.kernel.completer import Completer +from splash.kernel.inspections import Inspector def init_browser(): @@ -122,6 +123,7 @@ def __init__(self, **kwargs): self.lua.add_to_globals("splash", self.splash.get_wrapped()) self.runner = DeferredSplashRunner(self.lua, self.splash, self.sandboxed) #, self.log_msg) self.completer = Completer(self.lua) + self.inspector = Inspector(self.lua) # # try: # sys.stdout.write = self._print @@ -211,6 +213,9 @@ def error(failure): def do_complete(self, code, cursor_pos): return self.completer.complete(code, cursor_pos) + def do_inspect(self, code, cursor_pos, detail_level=0): + return self.inspector.help(code, cursor_pos, detail_level) + def _publish_execute_result(self, parent, data, metadata, execution_count): msg = { u'data': data, diff --git a/splash/kernel/lua_parser.py b/splash/kernel/lua_parser.py index 8db8dbe4c..c175a7469 100644 --- a/splash/kernel/lua_parser.py +++ b/splash/kernel/lua_parser.py @@ -34,13 +34,16 @@ def __repr__(self): class _AttrLookupMatch(_Match): + prefix_index = 0 + @property def prefix(self): - return self.value[0] + return self.value[self.prefix_index] @property def names_chain(self): - return self.value[1:][::-1] + start = self.prefix_index + 1 + return self.value[start:][::-1] def __repr__(self): return "%s(prefix=%r names_chain=%r)" % ( @@ -59,6 +62,13 @@ class SplashAttribute(_AttrLookupMatch): class SplashMethod(_AttrLookupMatch): pass +class SplashMethodOpenBrace(_AttrLookupMatch): + prefix_index = 1 + + @property + def brace(self): + return self.value[0] + class ObjectAttribute(_AttrLookupMatch): pass @@ -95,8 +105,8 @@ def __repr__(self): token_value = attrgetter("value") token_type = attrgetter("type") -def token(tp, check=lambda t: True): - return p.some(lambda t: t.type == tp and check(t)) >> token_value +def token(tp): + return p.some(lambda t: t.type == tp) >> token_value def flat(seq): res = [] @@ -135,8 +145,8 @@ def match(cls): iden_start = p.skip(p.some(lambda t: t.type not in ".:")) tok_splash = (p.a(Token("iden", "splash")) + iden_start) >> token_value -iden_nosplash = token("iden", lambda t: t.value != 'splash') iden = token("iden") +opt_iden = iden | p.pure("") # standalone names are parsed separately - we need e.g. to suggest them # as keywords @@ -145,7 +155,7 @@ def match(cls): # ("hello"):len constant_method = ConstantMethod.match( - (iden | p.pure("")) + + opt_iden + p.skip(colon) + p.skip(close_rnd_brace) + (tok_string | tok_number) + @@ -179,7 +189,7 @@ def match(cls): # foo["bar obj_attr_indexed = ObjectAttributeIndexed.match( - (iden | p.pure("")) + # FIXME: spaces in keys + opt_iden + # FIXME: spaces in keys quote + p.skip(open_sq_brace) + _obj @@ -187,27 +197,37 @@ def match(cls): # foo.bar:baz obj_method = ObjectMethod.match( - (iden | p.pure("")) + + opt_iden + p.skip(colon) + _obj ) # splash:meth splash_method = SplashMethod.match( - (iden_nosplash | p.pure("")) + + opt_iden + + p.skip(colon) + + tok_splash +) + +# splash:meth( +# splash:meth{ +splash_method_open_brace = SplashMethodOpenBrace.match( + (token("(") | token("{")) + + iden + p.skip(colon) + tok_splash ) # splash.attr splash_attr = SplashAttribute.match( - (iden_nosplash | p.pure("")) + + opt_iden + p.skip(dot) + tok_splash ) lua_parser = ( splash_method + | splash_method_open_brace | splash_attr | obj_method | obj_indexed_complete diff --git a/splash/tests/test_lua_parser.py b/splash/tests/test_lua_parser.py index f496c92b6..f1ba5bfa4 100644 --- a/splash/tests/test_lua_parser.py +++ b/splash/tests/test_lua_parser.py @@ -13,6 +13,7 @@ ObjectIndexedComplete, ConstantMethod, SplashMethod, + SplashMethodOpenBrace, SplashAttribute, ) from .test_completer import code_and_cursor_pos @@ -79,15 +80,28 @@ def parse(completer): ["(42):fo", ConstantMethod(["fo", 42])], ["42:fo", None], + # empty + ["(", None], + [".", None], + ["", None], + [" ", None], + ["45.", None], + ["45", None], + # splash-specific parsing ["splash:", SplashMethod(["", "splash"])], ["splash:x", SplashMethod(["x", "splash"])], + ["splash:x(", SplashMethodOpenBrace(["(", "x", "splash"])], + ["splash:x{", SplashMethodOpenBrace(["{", "x", "splash"])], + ["splash:x {", SplashMethodOpenBrace(["{", "x", "splash"])], + ["splash:{", None], ["splash.foo:x", ObjectMethod(["x", "foo", "splash"])], ["foo.splash:x", ObjectMethod(["x", "splash", "foo"])], ["splash.", SplashAttribute(["", "splash"])], ["splash.x", SplashAttribute(["x", "splash"])], ["splash.foo.x", ObjectAttribute(["x", "foo", "splash"])], ["foo.splash.x", ObjectAttribute(["x", "splash", "foo"])], + ]) def test_parse(parse, code, result): assert parse(code) == result