diff --git a/Makefile b/Makefile index 6f06c8d..fc3026e 100644 --- a/Makefile +++ b/Makefile @@ -32,21 +32,20 @@ install: $(EXE) ## Generating docs -docs: - $(FENNEL) $(FENNELFLAGS) tools/get-docs.fnl $(GET_DOCS_FLAGS) +docs: src/fennel-ls/docs/generated/lua51.fnl \ + src/fennel-ls/docs/generated/lua52.fnl \ + src/fennel-ls/docs/generated/lua53.fnl \ + src/fennel-ls/docs/generated/lua54.fnl -XDG_DATA_HOME ?= $(HOME)/.local/share -DOCSET_DIR = $(XDG_DATA_HOME)/fennel-ls/docsets/ +src/fennel-ls/docs/generated/%.fnl: + mkdir -p build/ + mkdir -p src/fennel-ls/docs/generated/ + $(FENNEL) $(FENNELFLAGS) tools/generate-lua-docs.fnl ${*} > $@ -$(DOCSET_DIR)/love2d.lua: src/fennel-ls/docs/generated/love2d.fnl - mkdir -p $(DOCSET_DIR) - $(FENNEL) $(FENNELFLAGS) --compile $< > $@ - -src/fennel-ls/docs/generated/love2d.fnl: - $(FENNEL) $(FENNELFLAGS) tools/get-docs.fnl --generate-love2d - -# has to be separate for licensing reasons -docs-love2d: $(DOCSET_DIR)/love2d.lua +docs-love2d: + @echo "This has moved to a separate source. Please see the wiki:" + @echo "https://wiki.fennel-lang.org/LanguageServer" + @exit 1 rm-docs: rm -rf src/fennel-ls/docs/ diff --git a/README.md b/README.md index 058dc9a..3df9867 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ Provides intelligent editing features for fennel files. * [Packaging](docs/packaging.md) * [Writing your own lint](docs/linting.md) +For information about installing documentation data for 3rd-party libraries +like love2d or tic80 [see the wiki](https://wiki.fennel-lang.org/LanguageServer). + ## License fennel-ls is licensed under the MIT license. See LICENSE for more info. This repository also contains files from other projects: diff --git a/TODO.md b/TODO.md index e71d05d..1c1dacb 100644 --- a/TODO.md +++ b/TODO.md @@ -119,9 +119,9 @@ done, but these are the sort of enhancements I am thinking about. - [ ] external docsets - [X] load external docsets from ~/.local/share/fennel-ls/docsets/ - [X] warn on missing docset - - [ ] document how to download external docsets + - [X] document how to download external docsets - [ ] document how to create external docsets - - [ ] move love2d and tic80 to external docsets (published .... where?) + - [X] move love2d and tic80 to external docsets (published .... where?) - [ ] automatic downloading of external docsets - [ ] some kind of registry built-in? diff --git a/changelog.md b/changelog.md index 8e9f236..b500a77 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,9 @@ ## UNRELEASED / ??? ### Features + +* Support loading external docsets from disk. +* Extract TIC-80 docs to external docset. * Support `:lua-version` settings like `"lua5.4"` rather than requiring `"lua54"`. * Support `"union"` in `:lua-version` for globals present in any Lua version. * Support `"intersection"` in `:lua-version` for globals present in every Lua version. diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index beb3b62..3013a30 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -45,10 +45,7 @@ (collect [k v (pairs lua-versions.lua51)] (if (. lua-versions.lua54 k) (values k v)))) -(local libraries {:tic80 (require :fennel-ls.docs.generated.tic80)}) - -;; alias -(set libraries.tic-80 libraries.tic80) +(local libraries {}) (λ load-library [name] (let [path (.. data-dir name docset-ext)] @@ -57,8 +54,9 @@ (f:close) (docs)) _ {:status :not-found - :msg (string.format "Could not find docset for library %s at %s" - name path)}))) + :msg (string.format "Could not find docset for library %s at %s\nSee %s" + name path + "https://wiki.fennel-lang.org/LanguageServer")}))) (λ get-library [name] (when (not (. libraries name)) diff --git a/src/fennel-ls/docs/generated/lua51.fnl b/src/fennel-ls/docs/generated/lua51.fnl index 8a79fe6..ea1565d 100644 --- a/src/fennel-ls/docs/generated/lua51.fnl +++ b/src/fennel-ls/docs/generated/lua51.fnl @@ -1,4 +1,5 @@ -;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.1/manual.html +;; auto-generated by `make docs` from fennel-ls. Contents come from +;; https://www.lua.org/manual/5.1/manual.html ;; Lua Lua 5.1 Reference Manual last updated Thu Aug 29 20:43:58 UTC 2019 (local docs {:_G {:binding "_G" :metadata {:fls/itemKind "Variable" diff --git a/src/fennel-ls/docs/generated/lua52.fnl b/src/fennel-ls/docs/generated/lua52.fnl index 321948b..03959c7 100644 --- a/src/fennel-ls/docs/generated/lua52.fnl +++ b/src/fennel-ls/docs/generated/lua52.fnl @@ -1,4 +1,5 @@ -;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.2/manual.html +;; auto-generated by `make docs` from fennel-ls. Contents come from +;; https://www.lua.org/manual/5.2/manual.html ;; Lua Lua 5.2 Reference Manual last updated Thu Aug 29 20:10:02 UTC 2019 (local docs {:_G {:binding "_G" :metadata {:fls/itemKind "Variable" diff --git a/src/fennel-ls/docs/generated/lua53.fnl b/src/fennel-ls/docs/generated/lua53.fnl index e332814..d7a819d 100644 --- a/src/fennel-ls/docs/generated/lua53.fnl +++ b/src/fennel-ls/docs/generated/lua53.fnl @@ -1,4 +1,5 @@ -;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.3/manual.html +;; auto-generated by `make docs` from fennel-ls. Contents come from +;; https://www.lua.org/manual/5.3/manual.html ;; Lua Lua 5.3 Reference Manual last updated Tue Jul 14 10:32:39 UTC 2020 (local docs {:_G {:binding "_G" :metadata {:fls/itemKind "Variable" diff --git a/src/fennel-ls/docs/generated/lua54.fnl b/src/fennel-ls/docs/generated/lua54.fnl index 9553ece..838565f 100644 --- a/src/fennel-ls/docs/generated/lua54.fnl +++ b/src/fennel-ls/docs/generated/lua54.fnl @@ -1,4 +1,5 @@ -;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.4/manual.html +;; auto-generated by `make docs` from fennel-ls. Contents come from +;; https://www.lua.org/manual/5.4/manual.html ;; Lua Lua 5.4 Reference Manual last updated Thu Jun 13 22:15:52 UTC 2024 (local docs {:_G {:binding "_G" :metadata {:fls/itemKind "Variable" diff --git a/src/fennel-ls/docs/generated/tic80.fnl b/src/fennel-ls/docs/generated/tic80.fnl deleted file mode 100644 index 4819d27..0000000 --- a/src/fennel-ls/docs/generated/tic80.fnl +++ /dev/null @@ -1,418 +0,0 @@ -;; auto-generated by `make docs` from fennel-ls. Contents come from https://tic80.com/learn -{:BDR {:binding "BDR" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["row"] - :fnl/docstring "Allows you to execute code between the drawing of each fullscreen scanline, for example, to manipulate the palette. -"}} - :BOOT {:binding "BOOT" - :metadata {:fls/itemKind "Function" - :fnl/docstring "Startup function. -"}} - :MENU {:binding "MENU" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["index"] - :fnl/docstring "Game Menu handler. -"}} - :SCN {:binding "SCN" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["row"] - :fnl/docstring "Allows you to execute code between the drawing of each scanline, for example, to manipulate the palette. -"}} - :TIC {:binding "TIC" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "Main function. It's called at 60fps (60 times every second). -"}} - :btn {:binding "btn" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["id"] - :fnl/docstring "This function allows you to read the status of one of the buttons attached to TIC. -The function returns true if the key with the supplied id is currently in the pressed state. -It remains true for as long as the key is held down. -If you want to test if a key was just pressed, use `btnp()` instead. -"}} - :btnp {:binding "btnp" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["id" "?hold" "?period"] - :fnl/docstring "This function allows you to read the status of one of TIC's buttons. -It returns true only if the key has been pressed since the last frame. -You can also use the optional hold and period parameters which allow you to check if a button is being held down. -After the time specified by hold has elapsed, btnp will return true each time period is passed if the key is still down. -For example, to re-examine the state of button `0` after 2 seconds and continue to check its state every 1/10th of a second, you would use btnp(0, 120, 6). -Since time is expressed in ticks and TIC runs at 60 frames per second, we use the value of 120 to wait 2 seconds and 6 ticks (ie 60/10) as the interval for re-checking. -"}} - :circ {:binding "circ" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "radius" "color"] - :fnl/docstring "This function draws a filled circle of the desired radius and color with its center at x, y. -It uses the Bresenham algorithm. -"}} - :circb {:binding "circb" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "radius" "color"] - :fnl/docstring "Draws the circumference of a circle with its center at x, y using the radius and color requested. -It uses the Bresenham algorithm. -"}} - :clip {:binding "clip" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "width" "height"] - :fnl/docstring "This function limits drawing to a clipping region or `viewport` defined by x,y,w,h. -Things drawn outside of this area will not be visible. -Calling clip() with no parameters will reset the drawing area to the entire screen. -"}} - :cls {:binding "cls" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?color"] - :fnl/docstring "Clear the screen. -When called this function clear all the screen using the color passed as argument. -If no parameter is passed first color (0) is used. -"}} - :elli {:binding "elli" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "a" "b" "color"] - :fnl/docstring "This function draws a filled ellipse of the desired a, b radiuses and color with its center at x, y. -It uses the Bresenham algorithm. -"}} - :ellib {:binding "ellib" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "a" "b" "color"] - :fnl/docstring "This function draws an ellipse border with the desired radiuses a b and color with its center at x, y. -It uses the Bresenham algorithm. -"}} - :exit {:binding "exit" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "Interrupts program execution and returns to the console when the TIC function ends. -"}} - :fget {:binding "fget" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["sprite_id" "flag"] - :fnl/docstring "Returns true if the specified flag of the sprite is set. See `fset()` for more details. -"}} - :font {:binding "font" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["text" - "x" - "y" - "chromakey" - "char_width" - "char_height" - "?fixed" - "?scale" - "?alt"] - :fnl/docstring "Print string with font defined in foreground sprites. -To simply print to the screen, check out `print()`. -To print to the console, check out `trace()`. -"}} - :fset {:binding "fset" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["sprite_id" "flag" "bool"] - :fnl/docstring "Each sprite has eight flags which can be used to store information or signal different conditions. -For example, flag 0 might be used to indicate that the sprite is invisible, flag 6 might indicate that the flag should be draw scaled etc. -See algo `fget()`. -"}} - :key {:binding "key" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?code"] - :fnl/docstring "The function returns true if the key denoted by keycode is pressed. -"}} - :keyp {:binding "keyp" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?code" "?hold" "?period"] - :fnl/docstring "This function returns true if the given key is pressed but wasn't pressed in the previous frame. -Refer to `btnp()` for an explanation of the optional hold and period parameters. -"}} - :line {:binding "line" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x0" "y0" "x1" "y1" "color"] - :fnl/docstring "Draws a straight line from point (x0,y0) to point (x1,y1) in the specified color. -"}} - :map {:binding "map" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?x" - "?y" - "?w" - "?h" - "?sx" - "?sy" - "?colorkey" - "?scale" - "?remap"] - :fnl/docstring "The map consists of cells of 8x8 pixels, each of which can be filled with a sprite using the map editor. -The map can be up to 240 cells wide by 136 deep. -This function will draw the desired area of the map to a specified screen position. -For example, map(5,5,12,10,0,0) will draw a 12x10 section of the map, starting from map coordinates (5,5) to screen position (0,0). -The map function's last parameter is a powerful callback function for changing how map cells (sprites) are drawn when map is called. -It can be used to rotate, flip and replace sprites while the game is running. -Unlike mset, which saves changes to the map, this special function can be used to create animated tiles or replace them completely. -Some examples include changing sprites to open doorways, hiding sprites used to spawn objects in your game and even to emit the objects themselves. -The tilemap is laid out sequentially in RAM - writing 1 to 0x08000 will cause tile(sprite) #1 to appear at top left when map() is called. -To set the tile immediately below this we need to write to 0x08000 + 240, ie 0x080F0. -"}} - :memcpy {:binding "memcpy" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["dest" "source" "size"] - :fnl/docstring "This function allows you to copy a continuous block of TIC's 96K RAM from one address to another. -Addresses are specified are in hexadecimal format, values are decimal. -"}} - :memset {:binding "memset" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["dest" "value" "size"] - :fnl/docstring "This function allows you to set a continuous block of any part of TIC's RAM to the same value. -The address is specified in hexadecimal format, the value in decimal. -"}} - :mget {:binding "mget" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y"] - :fnl/docstring "Gets the sprite id at the given x and y map coordinate. -"}} - :mouse {:binding "mouse" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "This function returns the mouse coordinates and a boolean value for the state of each mouse button,with true indicating that a button is pressed. -"}} - :mset {:binding "mset" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "tile_id"] - :fnl/docstring "This function will change the tile at the specified map coordinates. -By default, changes made are only kept while the current game is running. -To make permanent changes to the map, see `sync()`. -Related: `map()` `mget()` `sync()`. -"}} - :music {:binding "music" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?track" - "?frame" - "?row" - "?loop" - "?sustain" - "?tempo" - "?speed"] - :fnl/docstring "This function starts playing a track created in the Music Editor. -Call without arguments to stop the music. -"}} - :peek {:binding "peek" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr" "?bits"] - :fnl/docstring "This function allows to read the memory from TIC. -It's useful to access resources created with the integrated tools like sprite, maps, sounds, cartridges data? -Never dream to sound a sprite? -Address are in hexadecimal format but values are decimal. -To write to a memory address, use `poke()`. -`bits` allowed to be 1,2,4,8. -"}} - :peek1 {:binding "peek1" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr"] - :fnl/docstring "This function enables you to read single bit values from TIC's RAM. -The address is often specified in hexadecimal format. -"}} - :peek2 {:binding "peek2" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr"] - :fnl/docstring "This function enables you to read two bits values from TIC's RAM. -The address is often specified in hexadecimal format. -"}} - :peek4 {:binding "peek4" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr"] - :fnl/docstring "This function enables you to read values from TIC's RAM. -The address is often specified in hexadecimal format. -See 'poke4()' for detailed information on how nibble addressing compares with byte addressing. -"}} - :pix {:binding "pix" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "color"] - :fnl/docstring "This function can read or write pixel color values. -When called with a color parameter, the pixel at the specified coordinates is set to that color. -Calling the function without a color parameter returns the color of the pixel at the specified position. -"}} - :pmem {:binding "pmem" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["index" "value"] - :fnl/docstring "This function allows you to save and retrieve data in one of the 256 individual 32-bit slots available in the cartridge's persistent memory. -This is useful for saving high-scores, level advancement or achievements. -The data is stored as unsigned 32-bit integers (from 0 to 4294967295). - -Tips: -- pmem depends on the cartridge hash (md5), so don't change your lua script if you want to keep the data. -- Use `saveid:` with a personalized string in the header metadata to override the default MD5 calculation. -This allows the user to update a cart without losing their saved data. -"}} - :poke {:binding "poke" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr" "value" "?bits"] - :fnl/docstring "This function allows you to write a single byte to any address in TIC's RAM. -The address should be specified in hexadecimal format, the value in decimal. -`bits` allowed to be 1,2,4,8. -"}} - :poke1 {:binding "poke1" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr" "value"] - :fnl/docstring "This function allows you to write single bit values directly to RAM. -The address is often specified in hexadecimal format. -"}} - :poke2 {:binding "poke2" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr" "value"] - :fnl/docstring "This function allows you to write two bits values directly to RAM. -The address is often specified in hexadecimal format. -"}} - :poke4 {:binding "poke4" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["addr" "value"] - :fnl/docstring "This function allows you to write directly to RAM. -The address is often specified in hexadecimal format. -For both peek4 and poke4 RAM is addressed in 4 bit segments (nibbles). -Therefore, to access the the RAM at byte address 0x4000 -you would need to access both the 0x8000 and 0x8001 nibble addresses. -"}} - :print {:binding "print" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["text" - "?x" - "?y" - "?color" - "?fixed" - "?scale" - "?smallfont"] - :fnl/docstring "This will simply print text to the screen using the font defined in config. -When set to true, the fixed width option ensures that each character will be printed in a `box` of the same size, so the character `i` will occupy the same width as the character `w` for example. -When fixed width is false, there will be a single space between each character. - -Tips: -- To use a custom rastered font, check out `font()`. -- To print to the console, check out `trace()`. -"}} - :rect {:binding "rect" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "w" "h" "color"] - :fnl/docstring "This function draws a filled rectangle of the desired size and color at the specified position. -If you only need to draw the the border or outline of a rectangle (ie not filled) see `rectb()`. -"}} - :rectb {:binding "rectb" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x" "y" "w" "h" "color"] - :fnl/docstring "This function draws a one pixel thick rectangle border at the position requested. -If you need to fill the rectangle with a color, see `rect()` instead. -"}} - :reset {:binding "reset" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "Resets the cartridge. To return to the console, see the `exit()`. -"}} - :sfx {:binding "sfx" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["id" - "?note" - "?duration" - "?channel" - "?volume" - "?speed"] - :fnl/docstring "This function will play the sound with `id` created in the sfx editor. -Calling the function with id set to -1 will stop playing the channel. -The note can be supplied as an integer between 0 and 95 (representing 8 octaves of 12 notes each) or as a string giving the note name and octave. -For example, a note value of `14` will play the note `D` in the second octave. -The same note could be specified by the string `D-2`. -Note names consist of two characters, the note itself (in upper case) followed by `-` to represent the natural note or `#` to represent a sharp. -There is no option to indicate flat values. -The available note names are therefore: C-, C#, D-, D#, E-, F-, F#, G-, G#, A-, A#, B-. -The `octave` is specified using a single digit in the range 0 to 8. -The `duration` specifies how many ticks to play the sound for since TIC-80 runs at 60 frames per second, a value of 30 represents half a second. -A value of -1 will play the sound continuously. -The `channel` parameter indicates which of the four channels to use. Allowed values are 0 to 3. -The `volume` can be between 0 and 15. -The `speed` in the range -4 to 3 can be specified and means how many `ticks+1` to play each step, so speed==0 means 1 tick per step. -"}} - :spr {:binding "spr" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["id" - "x" - "y" - "?colorkey" - "?scale" - "?flip" - "?rotate" - "?w" - "?h"] - :fnl/docstring "Draws the sprite number index at the x and y coordinate. -You can specify a colorkey in the palette which will be used as the transparent color or use a value of -1 for an opaque sprite. -The sprite can be scaled up by a desired factor. For example, a scale factor of 2 means an 8x8 pixel sprite is drawn to a 16x16 area of the screen. -You can flip the sprite where: -- 0 = No Flip -- 1 = Flip horizontally -- 2 = Flip vertically -- 3 = Flip both vertically and horizontally -When you rotate the sprite, it's rotated clockwise in 90 steps: -- 0 = No rotation -- 1 = 90 rotation -- 2 = 180 rotation -- 3 = 270 rotation -You can draw a composite sprite (consisting of a rectangular region of sprites from the sprite sheet) by specifying the `w` and `h` parameters (which default to 1). -"}} - :sync {:binding "sync" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["?mask" "?bank" "?tocart"] - :fnl/docstring "The pro version of TIC-80 contains 8 memory banks. -To switch between these banks, sync can be used to either load contents from a memory bank to runtime, or save contents from the active runtime to a bank. -The function can only be called once per frame.If you have manipulated the runtime memory (e.g. by using mset), you can reset the active state by calling sync(0,0,false). -This resets the whole runtime memory to the contents of bank 0.Note that sync is not used to load code from banks; this is done automatically. -"}} - :time {:binding "time" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "This function returns the number of milliseconds elapsed since the cartridge began execution. -Useful for keeping track of time, animating items and triggering events. -"}} - :trace {:binding "trace" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["message" "?color"] - :fnl/docstring "This is a service function, useful for debugging your code. -It prints the message parameter to the console in the (optional) color specified. - -Tips: -- The Lua concatenator for strings is .. (two points). -- Use console cls command to clear the output from trace. -"}} - :tri {:binding "tri" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"] - :fnl/docstring "This function draws a triangle filled with color, using the supplied vertices. -"}} - :trib {:binding "trib" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"] - :fnl/docstring "This function draws a triangle border with color, using the supplied vertices. -"}} - :tstamp {:binding "tstamp" - :metadata {:fls/itemKind "Function" - :fnl/arglist {} - :fnl/docstring "This function returns the number of seconds elapsed since January 1st, 1970. -Useful for creating persistent games which evolve over time between plays. -"}} - :ttri {:binding "ttri" - :metadata {:fls/itemKind "Function" - :fnl/arglist ["x1" - "y1" - "x2" - "y2" - "x3" - "y3" - "u1" - "v1" - "u2" - "v2" - "u3" - "v3" - "?texsrc" - "?chromakey" - "?z1" - "?z2" - "?z3"] - :fnl/docstring "It renders a triangle filled with texture from image ram, map ram or vbank. -Use in 3D graphics. -In particular, if the vertices in the triangle have different 3D depth, you may see some distortion. -These can be thought of as the window inside image ram (sprite sheet), map ram or another vbank. -Note that the sprite sheet or map in this case is treated as a single large image, with U and V addressing its pixels directly, rather than by sprite ID. -So for example the top left corner of sprite #2 would be located at u=16, v=0. -"}}} diff --git a/test/hover.fnl b/test/hover.fnl index 422f33e..48b84cb 100644 --- a/test/hover.fnl +++ b/test/hover.fnl @@ -179,9 +179,6 @@ except that it sets a new message handler `msgh`.") nil) (fn test-libraries [] - (check "#(trac|e :hello)" - #($:find "a service function") - {:libraries {:tic80 true}}) (check "(trans|late \"hello\" :en :zh)" #($:find "convert from one lanugage to another") {:libraries {:external true}}) diff --git a/test/settings.fnl b/test/settings.fnl index 666a68c..886a0ca 100644 --- a/test/settings.fnl +++ b/test/settings.fnl @@ -53,14 +53,6 @@ (faith.not= [] bad)) nil) -(fn test-native-libaries [] - (let [{:diagnostics bad} (create-client {:main.fnl "(print btn)" - :flsproject.fnl "{}"}) - {:diagnostics good} (create-client {:main.fnl "(print btn)" - :flsproject.fnl "{:libraries {:tic-80 true}}"})] - (faith.not= [] bad) - (faith.= [] good))) - (fn test-editing-settings [] (let [{: client : uri} (create-client {:main.fnl "" :flsproject.fnl "{}"}) @@ -74,5 +66,4 @@ {: test-path : test-extra-globals : test-lints - : test-native-libaries : test-editing-settings} diff --git a/tools/generate-lua-docs.fnl b/tools/generate-lua-docs.fnl new file mode 100644 index 0000000..854ca61 --- /dev/null +++ b/tools/generate-lua-docs.fnl @@ -0,0 +1,227 @@ +"Script to generate /src/fennel-ls/docs/lua54.fnl and friends automatically" + +(local fennel (require :fennel)) +(local util (require :tools.util)) + +(local index-pattern "

.%.1 – Basic Functions.-\n") + +(fn parse-html [html] + "splits the lua manual into the relevant sections" + (let [begin-index (assert (html:find index-pattern) "no basic functions?") + end-index (assert (html:find "

. –

.-\n" (+ prev 1)) + section (stdlib:sub prev (if header (- header 1)))] + (let [index (section:find "

")] + (if index + (do + (table.insert fields (section:sub 1 (- index 1))) + (table.insert modules (section:sub index))) + (table.insert fields section))) + (when header (loop header)))) + + + (fn make-title [name] + (.. "

" name "

\n")) + ;; Artificially insert the `arg` docs. + ;; This isn't present in the "Basic Functions" part of the manual, but is + ;; still useful to be included in the docs. + (let [arg-signature (make-title :arg) + desc (-> html + ;; The goal here is to extract the smallest string which: + ;; 1) contains the string "global table called arg" + ;; 2) ends with "\n

" (not inclusive) + ;; 3) begins with "\n

" (not inclusive) + + ;; This match fufills 1 and 2 + (: :match "(.*global table called arg.-)\n

") + ;; trust me, I tried everything. + ;; The best way to do 3 is a non-greedy search in reverse + (: :reverse) + (: :match "(.-)>p<\n") + (: :reverse))] + (table.insert fields (.. arg-signature desc))) + (table.insert fields (.. (make-title "io.stdin") "stdin file")) + (table.insert fields (.. (make-title "io.stdout") "stdout file")) + (table.insert fields (.. (make-title "io.stderr") "stderr file")) + (loop (stdlib:find "


.-\n")) + (values modules fields last-update))) + +(fn html-to-markdown [str] + (let [str (-> str + ;; delete

tags + (: :gsub "" "") + ;; tags for the rest + (: :gsub "\"(.-)\"" "`\"%1\"`") + (: :gsub "\'(.-)\'" "`\"%1\"`") + (: :gsub "(.-)" "`%1`") + ;; supremum to unicode + (: :gsub "x" "ˣ") + (: :gsub "e" "ᵉ") + (: :gsub "y" "ʸ") + (: :gsub "51" "⁵¹") + (: :gsub "32" "³²") + ; ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖ𐞥ʳˢᵗᵘᵛʷˣʸᶻ + ;; bold to ** + (: :gsub "([^<]+)" "*%1*") + (: :gsub "([^<]+)" "**%1**") + ;; defeat all the links + (: :gsub "([^<]+)" "%1") + (: :gsub "([^<]+)" "%1") + (: :gsub "([^<]+)" "%1") + (: :gsub "See [^<]+[^%.]+%." "") + (: :gsub "[ \n]%(see [^<]+%)." "") + (: :gsub "[ \n]%([^<]+%)." "") + ;; code blocks + (: :gsub "

\n?([^<]-)\n?
" "```lua\n%1\n```") + ;; list items to indented * thingies + (: :gsub "
  • ([^<]+)
  • " + #(.. "* " (: ($:match "^\n*(.-)\n*$") :gsub "\n" "\n "))) + (: :gsub "" "")) + ;; check to ensure that all the tags have been defeated + tag (str:match "<[^>]+>[^>]+>")] + (when tag (error (.. "unhandled tag:" tag "\n" str))) + (-> str + ;; trim whitespace + (: :match "^%s*(.-)%s*$") + ;; html things + (: :gsub " " " ") + (: :gsub "–" "–") + (: :gsub "—" "—") + ;; For some reason, they use an html middot, but we want to use periods. + (: :gsub "···" "...") + (: :gsub ">" ">") + (: :gsub "<" "<") + (: :gsub "&" "<") + (: :gsub "π" "π") + (: :gsub "\n\n+" "\n\n")))) + +(fn parse-h3-section [html] + "parse a section that starts with an h3 tag. These are individual functions/variables." + (let [(header description) (html:match "^(.-)\n+(.-)\n*$") + optional-args [] + signature (header:match "(.-)") + ;; strip commas + signature (signature:gsub "," " ") + ;; Replace `[]`'d args with ?-prefixes + ;; Three times is enough, as `table.concat` and `load` and `loadfile` + ;; and `utf8.codepoint` and `utf8.len` have 3 sets of []'s. + ;; Lua 5.2 manual has a typo, so the last pass makes the `]` optional. + signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%](%]-%))" + #(do (table.insert optional-args $1) + (.. :? $1 $2 $3))) + signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%](%]-%))" + #(do (table.insert optional-args $1) + (.. :? $1 $2 $3))) + signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%]?(%]-%))" + #(do (table.insert optional-args $1) + (.. :? $1 $2 $3))) + ;; hide the thread argument in the debug functions + signature (if (signature:find "debug") + (signature:gsub "%[thread -%]" "") + signature) + ;; hide the ?pos argument in table.insert + signature (if (signature:find "table%.insert") + (signature:gsub "%[pos -%]" "") + signature) + ;; For some reason, they use an html middot, but we want to use periods. + signature (signature:gsub "···" "...") + ;; fix parens + signature (signature:gsub "^(.-) -%(" "(%1 ") + ;; fix spaces + signature (signature:gsub " +" " ") + signature (signature:gsub " +%)" ")") + signature-list (case (signature:match "^%((.-)%)$") + call (doto (icollect [arg (call:gmatch "[^ ]+")] + arg) + (table.remove 1))) + ;; tags for optional args + description (accumulate [desc description _ arg (ipairs optional-args)] + (desc:gsub (.. "" arg "") (.. "`?" arg "`"))) + ;; trim off the string pattern and string.pack/string.unpack format docs + description (description:gsub "\n[^\n]*

    .*" "") + description (html-to-markdown description) + name (signature:match "[^() ]+") + key (name:match "[^.:]+$") + ?module (and (name:find "[.:]") (name:match "^[^.:]+")) + kind (if (signature:find "[()]") :Function :Variable)] + + (values ?module + key + {:binding (signature:match "[^() ]+") + :metadata {:fnl/docstring description + :fnl/arglist signature-list + :fls/itemKind kind}}))) + +(fn parse-h2-section [html] + "parse a section that starts with an h2 tag. These are the main modules." + (let [(title description) (html:match "(.-)\n(.*)") + module-name (if (title:find "Coroutine") + "coroutine" + (title:find "Modules") + "package" + (title:find "String") + "string" + (title:find "UTF") + "utf8" + (title:find "Mathematical") + "math" + (title:find "Input and Output") + "io" + (title:find "Operating System") + "os" + (title:find "Debug") + "debug" + (title:find "Bitwise") + "bit32" + (title:find "Table") + "table") + description (html-to-markdown description)] + (assert module-name title) + (values module-name + {:binding module-name + :fields {} + :metadata {:fnl/docstring description + :fls/itemKind :Module}}))) + +(fn parse [input] + (let [version (input:match "Lua .- Reference Manual") + (modules module-items last-update) (parse-html input) + docs (collect [_ module (ipairs modules)] + (parse-h2-section module))] + (each [_ section (ipairs module-items)] + (let [(mod k v) (parse-h3-section section)] + (if (not mod) + (tset docs k v) + (not= mod "file") + (let [module-doc (. docs mod)] + (assert module-doc (.. mod " not found")) + (tset (. module-doc :fields) k v))))) + {: docs : last-update : version})) + +(fn render [{: docs : last-update : version}] + (.. ";; Lua " version " last updated " last-update "\n" + (fennel.view (fennel.list (fennel.sym :local) (fennel.sym :docs) docs)) + "\n(set docs._G.fields docs)\n" + "(set docs.io.fields.stdin.fields docs.io.fields)\n" + "(set docs.io.fields.stdout.fields docs.io.fields)\n" + "(set docs.io.fields.stderr.fields docs.io.fields)\n" + "docs")) + +(fn derive-docs-for [version] + (let [v (assert (version:match "^lua5(.)$") "Invalid Lua version.") + url (string.format "https://www.lua.org/manual/5.%d/manual.html" v) + doc-tbl (render (parse (with-open [file (util.curl-cached url)] + (file:read :*a))))] + (print ";; auto-generated by `make docs` from fennel-ls. Contents come from") + (print ";;" url) + (print doc-tbl))) + +(case arg + [version] (derive-docs-for version) + _ (do (io.stderr:write "USAGE: get-docs.fnl $VERSION\n") + (os.exit 1))) diff --git a/tools/get-deps.fnl b/tools/get-deps.fnl index eb067ec..27da844 100644 --- a/tools/get-deps.fnl +++ b/tools/get-deps.fnl @@ -1,4 +1,4 @@ -(local {: sh} (require :tools.util.sh)) +(local {: sh} (require :tools.util)) (fn git-clone [location url tag] (if tag diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl deleted file mode 100644 index 0fce89d..0000000 --- a/tools/get-docs.fnl +++ /dev/null @@ -1,44 +0,0 @@ -"Script to generate /src/fennel-ls/docs/lua54.fnl and friends automatically" - -(local {: sh} (require :tools.util.sh)) - -(fn curl-cached [url] - (let [filename (.. "build/" (url:gsub "[/:]" "_")) - file (io.open filename :r)] - (if file - file - (do - (sh "curl" url [">"] filename) - (io.open filename :r))))) - -(fn write-doc-file! [out-filename doc-src doc-tbl] - (assert doc-tbl - "bad argument #3, `doc-tbl` to write-doc-file! (expected string, got nil)") - (with-open [file (io.open (.. :src/fennel-ls/docs/generated/ out-filename) :w)] - (file:write ";; auto-generated by `make docs` from fennel-ls. Contents come from " - doc-src "\n" doc-tbl "\n"))) - -(fn derive-docs-from-url [url out-filename convert] - (write-doc-file! out-filename url - (convert (with-open [file (curl-cached url)] - (file:read :*a))))) - -;; a lot of this should maybe be moved to the makefile? -(fn main [] - (sh :mkdir :-p "build/") - (sh :mkdir :-p "src/fennel-ls/docs/generated/") - (let [generate-love2d-docs? (case arg ["--generate-love2d"] true _ false) - {:convert lua-manual} (require :tools.get-docs.lua-manual) - {:convert tic-manual} (require :tools.get-docs.tic80)] - (derive-docs-from-url "https://www.lua.org/manual/5.1/manual.html" "lua51.fnl" lua-manual) - (derive-docs-from-url "https://www.lua.org/manual/5.2/manual.html" "lua52.fnl" lua-manual) - (derive-docs-from-url "https://www.lua.org/manual/5.3/manual.html" "lua53.fnl" lua-manual) - (derive-docs-from-url "https://www.lua.org/manual/5.4/manual.html" "lua54.fnl" lua-manual) - (derive-docs-from-url "https://tic80.com/learn" :tic80.fnl tic-manual) - (when generate-love2d-docs? - (let [{:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] - (write-doc-file! :love2d.fnl - "https://github.com/love2d-community/love-api/" - (download-and-convert-love2d-manual!)))))) - -(main) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl deleted file mode 100644 index 3418392..0000000 --- a/tools/get-docs/love2d.fnl +++ /dev/null @@ -1,105 +0,0 @@ -(local fennel (require :fennel)) -(local {:clone git-clone} (require :tools.util.git)) - -(local love-api-build-directory :build/love-api) -(local require-love-api - (partial require (.. love-api-build-directory :/love_api))) - -; -; UTILS -; ----- -(fn build-lsp-value [name ?args ?docstring ?fields ?kind] - "Takes ... and returns a table to be used with the LSP." - (let [lsp-value {:binding name} - ?metadata (or ?args ?docstring)] - (when ?metadata (set lsp-value.metadata {})) - (when ?args (set lsp-value.metadata.fnl/arglist ?args)) - (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) - (when ?kind (set lsp-value.metadata.fls/itemKind ?kind)) - (when ?fields (set lsp-value.fields ?fields)) - lsp-value)) - -(fn clone-love-api! [] - (when (not (io.open :build/love-api)) - (git-clone love-api-build-directory - "https://github.com/love2d-community/love-api"))) - -(fn merge [...] - (let [arg-count (select "#" ...) - args [...]] - (if (= arg-count 0) - {} - (faccumulate [result {} i 1 arg-count] - (collect [k v (pairs (. args i)) &into result] - (values k v)))))) - -; -; PARSERS -; ------- -(fn get-fn-argument-names [fn-arguments] - "Given an array of arguments, return all names as an array." - (icollect [_i {:description _ : name :type _} (ipairs fn-arguments)] - name)) - -(fn format-description-of-fn-return-values [fn-returns] - (accumulate [x "\n\nReturns -" _i {: description : name :type return-type} (ipairs fn-returns)] - (.. x "\n" " * " name " (`" return-type "`) - " description))) - -(fn parse-first-fn-variant [[variant]] - "Given an array of fuction variants, format and return the first variant - for the LSP." - (collect [k v (pairs variant)] - (case k - :returns (values :returns (format-description-of-fn-return-values v)) - :arguments (values :args (get-fn-argument-names v))))) - -(fn get-all-love-api-functions [love-api] - [(table.unpack love-api.functions) (table.unpack love-api.callbacks)]) - -(fn love-functions->lsp-table [docs-tbl namespace] - (collect [_i value (ipairs docs-tbl)] - (let [{: name : description} value - binding (.. namespace name) - ?variants (?. value :variants) - ; LÖVE functions have several variants, e.g. different arities or - ; types; however, it's uncertain how to best display all of that - ; information, so the first is selected here as a reasonable default. - first-variant (if ?variants - (parse-first-fn-variant ?variants) - nil) - ?args (?. first-variant :args) - ?returns (or (?. first-variant :returns) "") - docstring (.. description ?returns)] - (values name (build-lsp-value binding ?args docstring nil :Function))))) - -(fn module-list->lsp-table [modules ?namespace] - (collect [_i module (ipairs modules)] - (let [{: name} module ; Other keys - :enum, :functions, :types - namespace (if ?namespace (.. ?namespace ".") "") - binding (.. namespace name) - ?docstring (?. module :description) - ?functions (?. module :functions) - ?modules (?. module :modules) - function-keys (if ?functions - (love-functions->lsp-table ?functions (.. binding ".")) - {}) - module-keys (if ?modules (module-list->lsp-table ?modules binding) {}) - fields (merge function-keys module-keys)] - (values name (build-lsp-value binding nil ?docstring fields :Module))))) - -(fn love-api->lsp-table [love-api] - (let [root-module {:description (.. "LÖVE is a framework for making 2D " - "games in the Lua programming language.") - :functions (get-all-love-api-functions love-api) - :modules love-api.modules - :name :love}] - (module-list->lsp-table [root-module]))) - -(fn convert [] - "Download documentation for the LÖVE framework via the love-api repo and - convert it to a Lua table usable for fennel-ls." - (clone-love-api!) - (let [love-api (require-love-api)] - (fennel.view (love-api->lsp-table love-api)))) - -{: convert} diff --git a/tools/get-docs/lua-manual.fnl b/tools/get-docs/lua-manual.fnl deleted file mode 100644 index 2af811d..0000000 --- a/tools/get-docs/lua-manual.fnl +++ /dev/null @@ -1,206 +0,0 @@ -(fn parse-html [html] - "splits the lua manual into the relevant sections" - (let [begin-index (assert (html:find "

    .%.1 – Basic Functions.-\n") "no basic functions?") - end-index (assert (html:find "

    . –

    .-\n" (+ prev 1)) - section (stdlib:sub prev (if header (- header 1)))] - (let [index (section:find "

    ")] - (if index - (do - (table.insert fields (section:sub 1 (- index 1))) - (table.insert modules (section:sub index))) - (table.insert fields section))) - (when header (loop header)))) - - - (fn make-title [name] - (.. "

    " name "

    \n")) - ;; Artificially insert the `arg` docs. - ;; This isn't present in the "Basic Functions" part of the manual, but is still useful to be included in the docs. - (let [arg-signature (make-title :arg) - arg-description (-> html - ;; The goal here is to extract the smallest string which: - ;; 1) contains the string "global table called arg" - ;; 2) ends with "\n

    " (not inclusive) - ;; 3) begins with "\n

    " (not inclusive) - - ;; This match fufills 1 and 2 - (: :match "(.*global table called arg.-)\n

    ") - ;; trust me, I tried everything. - ;; The best way to do 3 is a non-greedy search in reverse - (: :reverse) - (: :match "(.-)>p<\n") - (: :reverse))] - (table.insert fields (.. arg-signature arg-description))) - (table.insert fields (.. (make-title "io.stdin") "stdin file")) - (table.insert fields (.. (make-title "io.stdout") "stdout file")) - (table.insert fields (.. (make-title "io.stderr") "stderr file")) - (loop (stdlib:find "


    .-\n")) - (values modules fields last-update))) - -(fn html-to-markdown [str] - (let [str - (-> str - ;; delete

    tags - (: :gsub "" "") - ;; tags for the rest - (: :gsub "\"(.-)\"" "`\"%1\"`") - (: :gsub "\'(.-)\'" "`\"%1\"`") - (: :gsub "(.-)" "`%1`") - ;; supremum to unicode - (: :gsub "x" "ˣ") - (: :gsub "e" "ᵉ") - (: :gsub "y" "ʸ") - (: :gsub "51" "⁵¹") - (: :gsub "32" "³²") - ; ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖ𐞥ʳˢᵗᵘᵛʷˣʸᶻ - ;; bold to ** - (: :gsub "([^<]+)" "*%1*") - (: :gsub "([^<]+)" "**%1**") - ;; defeat all the links - (: :gsub "([^<]+)" "%1") - (: :gsub "([^<]+)" "%1") - (: :gsub "([^<]+)" "%1") - (: :gsub "See [^<]+[^%.]+%." "") - (: :gsub "[ \n]%(see [^<]+%)." "") - (: :gsub "[ \n]%([^<]+%)." "") - ;; code blocks - (: :gsub "

    \n?([^<]-)\n?
    " "```lua\n%1\n```") - ;; list items to indented * thingies - (: :gsub "
  • ([^<]+)
  • " #(.. "* " (: ($:match "^\n*(.-)\n*$") :gsub "\n" "\n "))) - (: :gsub "" "")) - ;; check to ensure that all the tags have been defeated - tag (str:match "<[^>]+>[^>]+>")] - (when tag (error (.. "unhandled tag:" tag "\n" str))) - (-> str - ;; trim whitespace - (: :match "^%s*(.-)%s*$") - ;; html things - (: :gsub " " " ") - (: :gsub "–" "–") - (: :gsub "—" "—") - ;; For some reason, they use an html middot, but we want to use periods. - (: :gsub "···" "...") - (: :gsub ">" ">") - (: :gsub "<" "<") - (: :gsub "&" "<") - (: :gsub "π" "π") - (: :gsub "\n\n+" "\n\n")))) - -(fn parse-h3-section [html] - "parse a section that starts with an h3 tag. These are individual functions/variables." - (let [(header description) (html:match "^(.-)\n+(.-)\n*$") - optional-args [] - signature (header:match "(.-)") - ;; strip commas - signature (signature:gsub "," " ") - ;; Replace `[]`'d args with ?-prefixes - ;; Three times is enough, as `table.concat` and `load` and `loadfile` - ;; and `utf8.codepoint` and `utf8.len` have 3 sets of []'s. - ;; Lua 5.2 manual has a typo, so the last pass makes the `]` optional. - signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%](%]-%))" - #(do (table.insert optional-args $1) (.. :? $1 $2 $3))) - signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%](%]-%))" - #(do (table.insert optional-args $1) (.. :? $1 $2 $3))) - signature (signature:gsub "%[ -([^%[%] ]+)([^%[%]]-)%]?(%]-%))" - #(do (table.insert optional-args $1) (.. :? $1 $2 $3))) - ;; hide the thread argument in the debug functions - signature (if (signature:find "debug") (signature:gsub "%[thread -%]" "") signature) - ;; hide the ?pos argument in table.insert - signature (if (signature:find "table%.insert") (signature:gsub "%[pos -%]" "") signature) - ;; For some reason, they use an html middot, but we want to use periods. - signature (signature:gsub "···" "...") - ;; fix parens - signature (signature:gsub "^(.-) -%(" "(%1 ") - ;; fix spaces - signature (signature:gsub " +" " ") - signature (signature:gsub " +%)" ")") - signature-list (case (signature:match "^%((.-)%)$") - call (doto (icollect [arg (call:gmatch "[^ ]+")] - arg) - (table.remove 1))) - ;; tags for optional args - description (accumulate [description description _ arg (ipairs optional-args)] - (description:gsub (.. "" arg "") - (.. "`?" arg "`"))) - ;; trim off the string pattern and string.pack/string.unpack format docs - description (description:gsub "\n[^\n]*

    .*" "") - description (html-to-markdown description) - name (signature:match "[^() ]+") - key (name:match "[^.:]+$") - ?module (and (name:find "[.:]") (name:match "^[^.:]+")) - kind (if (signature:find "[()]") :Function :Variable)] - - (values ?module - key - {:binding (signature:match "[^() ]+") - :metadata {:fnl/docstring description - :fnl/arglist signature-list - :fls/itemKind kind}}))) - -(fn parse-h2-section [html] - "parse a section that starts with an h2 tag. These are the main modules." - (let [(title description) (html:match "(.-)\n(.*)") - module-name (if (title:find "Coroutine") - "coroutine" - (title:find "Modules") - "package" - (title:find "String") - "string" - (title:find "UTF") - "utf8" - (title:find "Mathematical") - "math" - (title:find "Input and Output") - "io" - (title:find "Operating System") - "os" - (title:find "Debug") - "debug" - (title:find "Bitwise") - "bit32" - (title:find "Table") - "table") - description (html-to-markdown description)] - (assert module-name title) - (values module-name - {:binding module-name - :fields {} - :metadata {:fnl/docstring description - :fls/itemKind :Module}}))) - -(fn parse [input] - (let [version (input:match "Lua .- Reference Manual") - (modules module-items last-update) (parse-html input) - docs (collect [_ module (ipairs modules)] - (parse-h2-section module))] - (each [_ section (ipairs module-items)] - (let [(mod k v) (parse-h3-section section)] - (if (not mod) - (tset docs k v) - (not= mod "file") - (let [module-doc (. docs mod)] - (assert module-doc (.. mod " not found")) - (tset (. module-doc :fields) k v))))) - {: docs : last-update : version})) - -(fn render [{: docs : last-update : version}] - (let [{: view : sym : list} (require :fennel)] - (.. - ";; Lua " version " last updated " last-update "\n" - (view (list (sym :local) (sym :docs) docs)) "\n" - "(set docs._G.fields docs)\n" - "(set docs.io.fields.stdin.fields docs.io.fields)\n" - "(set docs.io.fields.stdout.fields docs.io.fields)\n" - "(set docs.io.fields.stderr.fields docs.io.fields)\n" - "docs"))) - -(fn convert [input] - (render (parse input))) - -{: convert} diff --git a/tools/get-docs/tic80.fnl b/tools/get-docs/tic80.fnl deleted file mode 100644 index 60408ea..0000000 --- a/tools/get-docs/tic80.fnl +++ /dev/null @@ -1,35 +0,0 @@ -(local fennel (require :fennel)) - -(fn remove-html-escape-codes [x] - (-> x - (: :gsub " " " ") - (: :gsub "–" "–") - (: :gsub "—" "—") - (: :gsub ">" ">") - (: :gsub "<" "<") - (: :gsub "&" "<") - (: :gsub "π" "π"))) - -(fn markdown->arglist [markdown] - (case (markdown:match "%(([^%)]*)%)") - signature - (icollect [arg (signature:gmatch "%S+")] - (case (arg:match "(.*)=") - argname (.. "?" argname) - _ arg)))) - -(fn markdown->data [html] - (let [api-markdown (html:match "## API functions.-### (.*)## Button IDs") - api-markdown (remove-html-escape-codes api-markdown)] - (collect [(name args docs) (api-markdown:gmatch - "([_%w]+)%s+`([^`]+)`%s(.-)\n### ")] - (let [arglist (markdown->arglist args)] - (values name {:metadata {:fnl/arglist arglist - :fnl/docstring docs - :fls/itemKind :Function} - :binding name}))))) - -(fn convert [contents] - (fennel.view (markdown->data contents))) - -{: convert} diff --git a/tools/util/sh.fnl b/tools/util.fnl similarity index 51% rename from tools/util/sh.fnl rename to tools/util.fnl index 86c6f32..739a515 100644 --- a/tools/util/sh.fnl +++ b/tools/util.fnl @@ -17,4 +17,19 @@ (print (.. "running command: " command)) (assert (os.execute command)))) -{: sh} +(fn clone [location url ?tag] + "Clones a git repository, given a location, url, and optional tag." + (assert location "Expected file location to clone git repository into.") + (assert url "Expected git repository url to clone.") + (if ?tag + (sh :git :clone :-c :advice.detachedHead=false :--depth=1 :--branch ?tag + url location) + (sh :git :clone :-c :advice.detachedHead=false :--depth=1 url location))) + +(fn curl-cached [url] + (let [filename (.. "build/" (url:gsub "[/:]" "_"))] + (or (io.open filename) + (do (sh "curl" url [">"] filename) + (io.open filename))))) + +{: sh : clone : curl-cached} diff --git a/tools/util/git.fnl b/tools/util/git.fnl deleted file mode 100644 index ebc9727..0000000 --- a/tools/util/git.fnl +++ /dev/null @@ -1,12 +0,0 @@ -(local {: sh} (require :tools.util.sh)) - -(fn clone [location url ?tag] - "Clones a git repository, given a location, url, and optional tag." - (assert location "Expected file location to clone git repository into.") - (assert url "Expected git repository url to clone.") - (if ?tag - (sh :git :clone :-c :advice.detachedHead=false :--depth=1 :--branch ?tag - url location) - (sh :git :clone :-c :advice.detachedHead=false :--depth=1 url location))) - -{: clone}