Skip to content

Instantly share code, notes, and snippets.

@wizard04wsu
Created October 4, 2022 16:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wizard04wsu/4122c5fba7af3f7b66a89874f531852d to your computer and use it in GitHub Desktop.
Save wizard04wsu/4122c5fba7af3f7b66a89874f531852d to your computer and use it in GitHub Desktop.
Tree-sitter build script for Atom
@echo off
:: Required version of tree-sitter-cli (TODO: update manually as needed)
set "treesitter=0.15.14"
::=======================================
:: Constants
::=======================================
:: console colors
set "nullChar="
set "cDefault=%nullChar%[0m"
set "cTeal=%nullChar%[36m"
set "cLime=%nullChar%[92m"
set "cGreen=%nullChar%[32m"
set "cYellow=%nullChar%[93m"
set "cRed=%nullChar%[91m"
set "cDarkRed=%nullChar%[31m"
set "cGray=%nullChar%[90m"
::=======================================
:: Options
::=======================================
:: Initialize the flags that determine what actions to take
set "doCleanup=0"
set "deleteBindingGyp=0"
set "doBuild=0"
set "displayVersions=0"
set "verbose=0"
set "out=2>nul"
set "out2=>&2"
:: Get the command line arguments (the options)
:params_loop
set "tmp=%~1"
if "%tmp%" == "" goto :params_end
if "%tmp%" == "-h" call :help & goto :end
if "%tmp%" == "--help" call :help & goto :end
if "%tmp%" == "-c" set "doCleanup=1"
if "%tmp%" == "--clean" set "doCleanup=1"
if "%tmp%" == "-r" set "deleteBindingGyp=1"
if "%tmp%" == "--regenerateBindingGyp" set "deleteBindingGyp=1"
if "%tmp%" == "-b" set "doBuild=1"
if "%tmp%" == "--build" set "doBuild=1"
if "%tmp%" == "-v" set "displayVersions=1"
if "%tmp%" == "--version" set "displayVersions=1"
if "%tmp%" == "--verbose" (
set "verbose=1"
set "out="
set "out2="
)
shift
goto :params_loop
:params_end
:: Check if a scanner file is present
set "hasScanner=0"
set "hasBindingGyp=0"
if exist "src\scanner.c*" (
set "hasScanner=1"
if exist "binding.gyp" set "hasBindingGyp=1"
)
::=======================================
:: Main
::=======================================
:: change directory to the short version of the path
::cd "%~dps0"
call :continue_versions
call :continue_cleanup
call :continue_generate
call :continue_build
goto :end
::=======================================
:: Help
::=======================================
:help
echo.
echo Tool for creating Tree-sitter parsers for use in the Atom code editor
echo.
echo Usage: ts [options]
echo.
echo Options:
echo -c, --clean Remove build files and other extraneous items
echo -r, --regenerateBindingGyp
echo Forcibly replace an existing "binding.gyp" file with a newly generated one
echo -b, --build Build the package using `electron-rebuild`
echo -v, --version Display the versions of Atom and its required dependencies
echo --verbose Show the output of all the commands
echo -h, --help Print this message
exit /b 0
::=======================================
:: Versions
::=======================================
:continue_versions
echo %cTeal%Checking requirements...%cDefault%
:: Get version numbers for Atom and relevant dependencies
call :getVersion_atom atom "Atom" %out%
call :getVersion_atom electron "Electron" %out%
call :getVersion_atom node "Node" %out%
call :getVersion_ts ts_installed %out%
call :getVersion_nan nan, nan_installed %out%
call :getVersion_node node_installed %out%
if "%ERRORLEVEL%" neq "0" (
set "tmp=%cRed%Node.js %node% is required"
if "%ERRORLEVEL%" == "1" (
:: node itself is installed, but the version does not match
set "tmp=%tmp% (%node_installed% installed)"
)
set "tmp=%tmp%%cDefault%"
call :displayVersions %out%
echo %tmp%
goto :end
)
if "%displayVersions%" == "1" call :displayVersions %out%
exit /b 0
:displayVersions
echo.
echo Versions:%cGray%
set "tmp= Atom %atom%"
echo %tmp%
set "tmp= Electron "
if "%electron%" neq "" (
set "tmp=%tmp%%electron%"
) else (
set "tmp=%tmp%%cDarkRed%not installed%cGray% (%electron% required)"
)
echo %tmp%
set "tmp= Node "
if "%node%" == "%node_installed%" (
set "tmp=%tmp%%node_installed%"
) else (
set "tmp=%tmp%%cDarkRed%%node_installed%%cGray% (%node% required)"
)
echo %tmp%
set "tmp= Tree-sitter "
if "%treesitter%" == "%ts_installed%" (
set "tmp=%tmp%%ts_installed%"
) else (
if "%ts_installed%" == "" (
set "tmp=%tmp%%cDarkRed%not installed%cGray%"
) else (
set "tmp=%tmp%%cDarkRed%%ts_installed%%cGray%"
)
set "tmp=%tmp% (%treesitter% required)"
)
echo %tmp%
set "tmp= nan "
if "%nan_installed%" neq "" (
set "tmp=%tmp%%nan_installed%"
) else (
set "tmp=%tmp%%cDarkRed%not installed%cGray%"
)
echo %tmp%
echo %cDefault%
exit /b 0
:getVersion_atom
set "tmp="
for /f "tokens=2 delims=:" %%a in ('atom --version ^| find "%~2"') do (set "tmp=%%a")
set "%~1=%tmp:~1%"
exit /b 0
:getVersion_node
call nvm current %out2%
if "%ERRORLEVEL%" neq "0" call :getVersion_node_alt
if "%ERRORLEVEL%" neq "0" exit /b %ERRORLEVEL%
:: nvm-windows is installed; get the version it's currently using
set "tmp="
for /f "tokens=1" %%a in ('nvm current') do (set "tmp=%%a")
set "%~1=%tmp:~1%"
exit /b 0
:getVersion_node_alt
:: nvm-windows is not installed; check if node itself is installed
call node --version %out2%
if "%ERRORLEVEL%" neq "0" (
:: node is not installed
set "%~1="
exit /b 2
)
:: node is installed; get the version
set "tmp="
for /f "tokens=1" %%a in ('node --version') do (set "tmp=%%a")
set "%~1=%tmp:~1%"
exit /b 1
:getVersion_ts
call tree-sitter --version %out% %out2%
if "%ERRORLEVEL%" neq "0" (
:: tree-sitter-cli is not installed
set "%~1="
exit /b 1
)
for /f "tokens=2" %%a in ('tree-sitter --version') do (set "%~1=%%a")
exit /b 0
:getVersion_nan
:: get the latest version number
for /f "tokens=1" %%a in ('npm view nan version') do (set "%~1=%%a")
:: get the currently installed version
for /f "tokens=2,3 delims=@ " %%a in ('npm ls nan') do (if "%%a" == "nan" set "%~2=%%b")
exit /b 0
::=======================================
:: Cleanup
::=======================================
:continue_cleanup
if "%doCleanup%" == "1" call :cleanup %out%
if "%deleteBindingGyp%" == "1" (
call :removeBindingGyp %out%
) else (
if "%hasScanner%" == "0" call :removeBindingGyp %out%
)
exit /b 0
:cleanup
echo %cTeal%Removing build files...%cDefault%
call :removeFiles %out2%
exit /b 0
:removeFiles
rmdir /S /Q "bin"
rmdir /S /Q "bindings\*"
rmdir /S /Q "bindings"
del "cargo.toml"
del "parser.exp"
del "parser.lib"
del "parser.obj"
del "scanner.obj"
rmdir /S /Q "build"
del "package-lock.json"
exit /b 0
:removeBindingGyp
echo %cTeal%Removing binding.gyp...%cDefault%
del "binding.gyp" %out2%
exit /b 0
::=======================================
:: Generate Parser
::=======================================
:continue_generate
:: Generate tree-sitter parser
call :generate %out%
if "%ERRORLEVEL%" neq "0" (
echo %cRed%Parser generation failed.%cDefault%
if "%out%" neq "" echo Run again with the %cTeal%--verbose%cDefault% option to see the output.
exit /b 1
)
echo %cLime%Parser generated.%cDefault%
exit /b 0
:generate
echo %cTeal%Updating dependencies...%cDefault%
call :installDependencies %out2%
echo %cTeal%Generating Tree-sitter parser...%cDefault%
call nvm use %node% %out2%
call tree-sitter generate %out2%
exit /b %ERRORLEVEL%
:installDependencies
if "%node%" neq "%node_installed%" (
call nvm install %node%
call nvm use %node%
echo Node %node%
)
if "%nan%" neq "%nan_installed%" (
call npm uninstall nan
call npm install nan
)
if "%treesitter%" neq "%ts_installed%" (
call npm uninstall tree-sitter-cli
call npm install -D tree-sitter-cli@%treesitter%
)
exit /b 0
::=======================================
:: Build Package
::=======================================
:continue_build
if "%doBuild%" == "0" exit /b 0
if "%hasScanner%" == "1" (
if "%hasBindingGyp%" == "0" (
:: binding.gyp did not exist and has been created; remind developer to add scanner; don't build
call :binding_reminder %out%
goto :end
) else (
if "%deleteBindingGyp%" == "1" (
:: binding.gyp was deleted, then newly created; remind developer to add scanner; don't build
call :binding_reminder %out%
goto :end
) else (
:: binding.gyp is unmodified; assume developer already added scanner; build if requested
if "%doBuild%" == "0" (
call :binding_reminder %out%
goto :end
)
)
)
)
call :build %out%
if "%ERRORLEVEL%" neq "0" (
echo %cRed%Package build failed.%cDefault%
if "%hasScanner%" == "1" (
echo %cYellow%Remember to include your scanner as a source in binding.gyp.%cDefault%
)
if "%out%" neq "" echo Run again with the %cTeal%--verbose%cDefault% option to see the output.
exit /b 1
)
echo %cLime%Package built.%cDefault%
exit /b 0
:binding_reminder
if "%doBuild%" == "1" (
echo %cRed%Package build was not attempted.%cDefault%
echo %cYellow%Remember to include your scanner as a source in binding.gyp.%cDefault%
) else (
echo %cYellow%Remember to include your scanner as a source in binding.gyp.%cDefault%
)
exit /b 0
:build
echo %cTeal%Building package...%cDefault%
call npm install -D electron-rebuild %out2%
for /f "delims=" %%a in (`electron-rebuild -v %electron%`) do (
:: there's output, so there was an error
echo %%a %out2%
exit /b 1
)
exit /b 0
:end
exit /b 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment