diff --git a/android/game.apk b/android/game.apk index 48cad1a..6721d82 100644 Binary files a/android/game.apk and b/android/game.apk differ diff --git a/android/game.love b/android/game.love index c74b242..c4b565a 100644 Binary files a/android/game.love and b/android/game.love differ diff --git a/android/tools/love-android-sdl2/AndroidManifest.xml b/android/tools/love-android-sdl2/AndroidManifest.xml index 78ddee2..a8409ae 100644 --- a/android/tools/love-android-sdl2/AndroidManifest.xml +++ b/android/tools/love-android-sdl2/AndroidManifest.xml @@ -1,5 +1,5 @@ - @@ -12,13 +12,13 @@ diff --git a/android/tools/love-android-sdl2/assets/game.love b/android/tools/love-android-sdl2/assets/game.love index c74b242..c4b565a 100644 Binary files a/android/tools/love-android-sdl2/assets/game.love and b/android/tools/love-android-sdl2/assets/game.love differ diff --git a/android/tools/love-android-sdl2/bin/AndroidManifest.xml b/android/tools/love-android-sdl2/bin/AndroidManifest.xml index 78ddee2..a8409ae 100644 --- a/android/tools/love-android-sdl2/bin/AndroidManifest.xml +++ b/android/tools/love-android-sdl2/bin/AndroidManifest.xml @@ -1,5 +1,5 @@ - @@ -12,13 +12,13 @@ diff --git a/android/tools/love-android-sdl2/bin/build.prop b/android/tools/love-android-sdl2/bin/build.prop index 82d2962..efe666a 100644 --- a/android/tools/love-android-sdl2/bin/build.prop +++ b/android/tools/love-android-sdl2/bin/build.prop @@ -1,5 +1,5 @@ #Last build type -#Thu, 08 Dec 2016 20:41:46 +0100 +#Mon, 26 Dec 2016 12:09:05 +0100 build.last.target=debug diff --git a/android/tools/love-android-sdl2/bin/classes.dex b/android/tools/love-android-sdl2/bin/classes.dex index c896b04..238fffc 100644 Binary files a/android/tools/love-android-sdl2/bin/classes.dex and b/android/tools/love-android-sdl2/bin/classes.dex differ diff --git a/android/tools/love-android-sdl2/bin/classes.dex.d b/android/tools/love-android-sdl2/bin/classes.dex.d index e67e708..912f3c9 100644 --- a/android/tools/love-android-sdl2/bin/classes.dex.d +++ b/android/tools/love-android-sdl2/bin/classes.dex.d @@ -1,9 +1,9 @@ /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes.dex : \ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/BuildConfig.class \ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/LtaActivity.class \ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$attr.class \ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$drawable.class \ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R.class \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/BuildConfig.class \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/LtaActivity.class \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$attr.class \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$drawable.class \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R.class \ /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/org/libsdl/app/DummyEdit.class \ /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/org/libsdl/app/SDLActivity$1.class \ /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/classes/org/libsdl/app/SDLActivity$2.class \ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$attr.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$attr.class deleted file mode 100644 index 87e83de..0000000 Binary files a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$attr.class and /dev/null differ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/BuildConfig.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/BuildConfig.class similarity index 74% rename from android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/BuildConfig.class rename to android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/BuildConfig.class index a5d9d9f..3a6dc2c 100644 Binary files a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/BuildConfig.class and b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/BuildConfig.class differ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/LtaActivity.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/LtaActivity.class similarity index 62% rename from android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/LtaActivity.class rename to android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/LtaActivity.class index ebdb93f..14f349b 100644 Binary files a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/LtaActivity.class and b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/LtaActivity.class differ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$attr.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$attr.class new file mode 100644 index 0000000..07d501a Binary files /dev/null and b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$attr.class differ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$drawable.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$drawable.class similarity index 56% rename from android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$drawable.class rename to android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$drawable.class index bc29197..577d896 100644 Binary files a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R$drawable.class and b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R$drawable.class differ diff --git a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R.class b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R.class similarity index 63% rename from android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R.class rename to android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R.class index d293e6e..c84a62c 100644 Binary files a/android/tools/love-android-sdl2/bin/classes/love/to/android1208204140/R.class and b/android/tools/love-android-sdl2/bin/classes/love/to/android1226120858/R.class differ diff --git a/android/tools/love-android-sdl2/bin/love_android_sdl2-debug-unaligned.apk b/android/tools/love-android-sdl2/bin/love_android_sdl2-debug-unaligned.apk index d123805..ac2a933 100644 Binary files a/android/tools/love-android-sdl2/bin/love_android_sdl2-debug-unaligned.apk and b/android/tools/love-android-sdl2/bin/love_android_sdl2-debug-unaligned.apk differ diff --git a/android/tools/love-android-sdl2/bin/love_android_sdl2-debug.apk b/android/tools/love-android-sdl2/bin/love_android_sdl2-debug.apk index 48cad1a..6721d82 100644 Binary files a/android/tools/love-android-sdl2/bin/love_android_sdl2-debug.apk and b/android/tools/love-android-sdl2/bin/love_android_sdl2-debug.apk differ diff --git a/android/tools/love-android-sdl2/bin/love_android_sdl2.ap_ b/android/tools/love-android-sdl2/bin/love_android_sdl2.ap_ index 2d00700..fa55576 100644 Binary files a/android/tools/love-android-sdl2/bin/love_android_sdl2.ap_ and b/android/tools/love-android-sdl2/bin/love_android_sdl2.ap_ differ diff --git a/android/tools/love-android-sdl2/bin/proguard.txt b/android/tools/love-android-sdl2/bin/proguard.txt index fb2b725..bb99f3e 100644 --- a/android/tools/love-android-sdl2/bin/proguard.txt +++ b/android/tools/love-android-sdl2/bin/proguard.txt @@ -1,9 +1,9 @@ # view AndroidManifest.xml #generated:45 --keep class love.to.android1208204140.DownloadActivity { (...); } +-keep class love.to.android1226120858.DownloadActivity { (...); } # view AndroidManifest.xml #generated:17 --keep class love.to.android1208204140.DownloadService { (...); } +-keep class love.to.android1226120858.DownloadService { (...); } # view AndroidManifest.xml #generated:18 --keep class love.to.android1208204140.LtaActivity { (...); } +-keep class love.to.android1226120858.LtaActivity { (...); } diff --git a/android/tools/love-android-sdl2/gen/R.java.d b/android/tools/love-android-sdl2/gen/R.java.d index 5ce8beb..5889185 100644 --- a/android/tools/love-android-sdl2/gen/R.java.d +++ b/android/tools/love-android-sdl2/gen/R.java.d @@ -1,3 +1,3 @@ -/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/gen/love/to/android1208204140/R.java \ +/Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/gen/love/to/android1226120858/R.java \ : /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/res/drawable-xxhdpi/ic_launcher.png \ /Users/androsfenollosa/www/alunizaje/android/tools/love-android-sdl2/bin/AndroidManifest.xml \ diff --git a/android/tools/love-android-sdl2/gen/love/to/android1208204140/BuildConfig.java b/android/tools/love-android-sdl2/gen/love/to/android1226120858/BuildConfig.java similarity index 79% rename from android/tools/love-android-sdl2/gen/love/to/android1208204140/BuildConfig.java rename to android/tools/love-android-sdl2/gen/love/to/android1226120858/BuildConfig.java index 98b743c..2c4d462 100644 --- a/android/tools/love-android-sdl2/gen/love/to/android1208204140/BuildConfig.java +++ b/android/tools/love-android-sdl2/gen/love/to/android1226120858/BuildConfig.java @@ -1,5 +1,5 @@ /** Automatically generated file. DO NOT MODIFY */ -package love.to.android1208204140; +package love.to.android1226120858; public final class BuildConfig { public final static boolean DEBUG = true; diff --git a/android/tools/love-android-sdl2/gen/love/to/android1208204140/R.java b/android/tools/love-android-sdl2/gen/love/to/android1226120858/R.java similarity index 91% rename from android/tools/love-android-sdl2/gen/love/to/android1208204140/R.java rename to android/tools/love-android-sdl2/gen/love/to/android1226120858/R.java index 4d0bacc..0eb0cf0 100644 --- a/android/tools/love-android-sdl2/gen/love/to/android1208204140/R.java +++ b/android/tools/love-android-sdl2/gen/love/to/android1226120858/R.java @@ -5,7 +5,7 @@ * should not be modified by hand. */ -package love.to.android1208204140; +package love.to.android1226120858; public final class R { public static final class attr { diff --git a/android/tools/love-android-sdl2/src/love/to/android1208204140/LtaActivity.java b/android/tools/love-android-sdl2/src/love/to/android1226120858/LtaActivity.java similarity index 69% rename from android/tools/love-android-sdl2/src/love/to/android1208204140/LtaActivity.java rename to android/tools/love-android-sdl2/src/love/to/android1226120858/LtaActivity.java index 807e4e8..8236598 100644 --- a/android/tools/love-android-sdl2/src/love/to/android1208204140/LtaActivity.java +++ b/android/tools/love-android-sdl2/src/love/to/android1226120858/LtaActivity.java @@ -1,4 +1,4 @@ -package love.to.android1208204140; +package love.to.android1226120858; import org.love2d.android.GameActivity; public class LtaActivity extends GameActivity {} diff --git a/android/tools/zbstudio.app/Contents/Info.plist b/android/tools/zbstudio.app/Contents/Info.plist deleted file mode 100644 index e234685..0000000 --- a/android/tools/zbstudio.app/Contents/Info.plist +++ /dev/null @@ -1,38 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ZeroBraneStudio - CFBundleDisplayName - ZeroBraneStudio - CFBundleGetInfoString - - CFBundleIconFile - zbstudio.icns - CFBundleIdentifier - com.ZeroBrane.ZeroBraneStudio - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - - CFBundleName - ZeroBraneStudio - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - - CSResourcesFileMapped - - LSRequiresCarbon - - NSHumanReadableCopyright - - - diff --git a/android/tools/zbstudio.app/Contents/MacOS/ZeroBraneStudio b/android/tools/zbstudio.app/Contents/MacOS/ZeroBraneStudio deleted file mode 100755 index 230655b..0000000 --- a/android/tools/zbstudio.app/Contents/MacOS/ZeroBraneStudio +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -ZBS_PATH=${0%/*/*} -if [ ! -d $ZBS_PATH ]; then ZBS_PATH=${PWD%/*}; fi -ZBS_BIN="$ZBS_PATH/ZeroBraneStudio/bin" -if [[ ! -e "$ZBS_BIN/libedit.3.dylib" && ! -e /usr/lib/libedit.3.dylib ]] -then ln -s /usr/lib/libedit.2.dylib "$ZBS_BIN/libedit.3.dylib"; fi -export DYLD_LIBRARY_PATH="$ZBS_BIN:${DYLD_LIBRARY_PATH}" -(cd "$ZBS_PATH/ZeroBraneStudio"; bin/lua src/main.lua zbstudio "$@") diff --git a/android/tools/zbstudio.app/Contents/Resources/zbstudio.icns b/android/tools/zbstudio.app/Contents/Resources/zbstudio.icns deleted file mode 100644 index 106c308..0000000 Binary files a/android/tools/zbstudio.app/Contents/Resources/zbstudio.icns and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/CHANGELOG.md b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/CHANGELOG.md deleted file mode 100644 index 549b37f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/CHANGELOG.md +++ /dev/null @@ -1,2364 +0,0 @@ -# ZeroBrane Studio Changelog - -## v1.30 (Jan 21 2016) - -### Highlights - - Added `markers` panel to show and navigate bookmarks and breakpoints. - - Added saving/restoring bookmarks and breakpoints. - - Added breakpoint prev/next navigation (`Project | Breakpoint` menu). - - Added find/replace in selection to search operations. - - Added printing of editor tabs and Console/Output windows (available on Windows and OSX). - - Added recursive processing of configuration files (using `include` command). - - Added `outline.showcompact` setting to keep outline more compact for large files. - - Added opening multiple files from the `Open` dialog. - - Updated Corona API for v2015.2731 and added handling of type inheritance. - - Updated love2d API for v0.10.0. - -### Special thanks - - To [tmiv](https://github.com/tmiv) for allowing shortcuts to be added to tools menu items. - - To [Yonaba](https://github.com/Yonaba/) for French translation update. - - To [Leo Bartoloni](https://github.com/bartoleo) for Italian translation update. - - To [Inigo Sola](https://github.com/inigosola) for Spanish translation update. - -### Improvements - - Added `CloneMenu` package method (#166). - - Added Torch and Redis debugging links. - - Added `IsNew` method for documents (#166). - - Added `Print` method and updated core components to use it during launch. - - Added skipping `UPDATE_CONTENT` events on cursor blinks in `UPDATEUI` (#419). - - Added preserving markers after sorting/reindentation operations. - - Added editor `MarkerGetAll` method (#166). - - Added example on how to set breakpoint shortcuts used in v1.20 or earlier (#419). - - Added processing of `include` command without extension in config (#555). - - Added reporting of missing packages when using `package` command in config (#555). - - Added processing of `package` command without extension in config (#555). - - Added hint on using updated breakpoint shortcut (#419). - - Added breakpoint prev/next navigation (#419). - - Added `AttachMenu` package method (#166). - - Added `MarkerToggle` editor method (#166). - - Added `MarkerGotoNext` and `MarkerGotoPrev` editor methods (#166). - - Added local menu to the `Markers` panel to toggle markers (#419). - - Added saving/restoring bookmarks and breakpoints (#419). - - Added `BookmarkToggle` method to the editor (#166). - - Added `BreakpointToggle` method to the editor (#166). - - Added `markers` panel to show bookmarks and breakpoints (#419). - - Added `onEditorMarkerUpdate` event (#166). - - Added unfolding fragments that include activated line during debugging (closes #575). - - Added skipping comment when none is provided in the Stack (instead of showing `nil`). - - Added skipping comments in the lexer to avoid splitting statements (fixes #568). - - Added `GetExePath` method for the interpreter (#166). - - Added package `GetFilePath` method (#166). - - Added `showhiddenfiles` option to show hidden files in the filetree (closes #561). - - Added package `RemovePanel` method (#166). - - Added loading of custom package from the config file (closes #555). - - Added `Alt-Enter` to "replace all" when replace field is selected in the search panel. - - Added setting project directory to the selected directory to the project tree menu. - - Added ignoring `Ctrl-CapsLock` in the editor that was shrinking the font. - - Added recursive processing of configuration files with relative names (#555). - - Added moving cursor to the end of the pasted fragment (#556). - - Added workaround for copying UTF-8 invalid data to/from clipboard (#260, #556). - - Added `CloseAll` and `CloseAllExcept` document methods (#166). - - Added warning in the interpreter when a short name not generated on Windows (closes #559). - - Added check for recover record to be fully present. - - Added using `*Raw` methods when available for handling of invalid UTF-8 chars (#260, #556). - - Added `FileRemove` method (#166). - - Added package `onAppDone` method (#166). - - Added sorting the list of known extensions. - - Added `outline.showcompact` setting to keep outline more compact for large files (closes #549). - - Added updating selection boundaries after replace-in-selection (#547). - - Added resizing toolbar background after resizing the application window. - - Added timing to the tests. - - Added context menu item to clear text in the Console window. - - Added context menu to select a (clicked on) command in the Console window. - - Added `onMenuConsole` event (#166). - - Added reporting printing progress (#540). - - Added package `IsValidProperty` method (#166). - - Added separator to the print-related menu items on OSX (#540). - - Added header/footer printing (#540). - - Added printing of the current editor tab (closes #540). - - Add package `GetIndicators` method (#166). - - Added `editor.wrapmode` to configure wrapping mode in the editor. - - Added reporting of another instance running under a different user (closes #542). - - Added opening multiple files from the `Open` dialog (closes #541). - - Allowed reading input in the Output window without printing something first (closes #538). - - Allow shortcuts to be added to tools menu items - - Extended PATH on OSX with `/usr/local/bin` to provide access to tools in that folder (#356). - - Improved compatibility when running the IDE using Lua 5.2. - - Improved handling of names with Unicode chars during debugging on Windows (#559). - - Limited requesting attention on debugging starts to happen when debugging is suspended. - - Moved wxlua version number to a better location in the About screen. - - Optimized path generation in directory traversal (#260). - - Removed a workaround for wxlua build issue as it's no longer needed. - - Replaced `ConsoleClear` with `Erase` methods for the Console object. - - Removed search panel from the list of floated panels as it shouldn't be there. - - Removed `allowinteractivescript` setting as it doesn't need to be configurable (#538). - - Replaced `EditorIsModified` with document method calls. - - Spanish translation updated - - Switched to using client size instead of system metric to get screen width (#260). - - Switched to using `KEY` event in search panel to make it work with wxwidgets 3.1+ (#260). - - Switched to per-editor tracking in `UPDATEUI` event. - - Updated `interpreter` menu to use a clone to avoid Linux assertion. - - Updated Italian Translation (closes #586). - - Updated french translation as of df381b5 (see #70) - - Updated Russian translation (#70). - - Updated translation files with new messages (#70). - - Updated LuaForWindows interpreter to accept command line parameters (#582). - - Updated LuaForWindows interpreter to properly pass `arg` to the script (closes #582). - - Updated `GetDocument` to not fail when no editor is passed. - - Updated live coding to group number updates together for `Undo`/`Redo` purposes. - - Updated `Toggle Breakpoint` and `Break` shortcuts for consistency (#419). - - Updated love2d API for v0.10.0 (#247). - - Updated script to process new love2d API format (with `variants`). - - Updated showing filename of the missing interpreter in the project list (#570). - - Updated build scripts to use own wxwidgets repository to better sync build versions (#260). - - Updated build scripts to remove an error from the check for missing methods in wxlua. - - Updated README to remove outdated .ini reference from Estrela section. - - Updated instructions in the `estrela` configuration file to reference `include` command. - - Updated luasec build script to use the latest openSSL version (1.0.2d). - - Updated UTF-8 validation to use wxwidgets libraries for better performance (#556). - - Updated clipboard copy to make non-UTF-8 data to work on OSX (#260, #556). - - Updated Console history to work with UTF-8 invalid strings (#260, #556). - - Updated `Ctrl/Shift-Ins` and `Shift-Del` to work in all editors (#260, #556). - - Updated `Output` and `Console` to display invalid characters as is (#260, #556). - - Updated config sample to remove no longer needed `G` references. - - Updated config processing to simplify access to global functions. - - Updated config processing to allow use of `package` field. - - Updated windows launcher code to use manifest for hidpi awareness. - - Updated `AddConfig` method to accept single filename in addition to a list (#166). - - Updated event handling to better handle events that are executed once (#260). - - Updated `sample` package events for more accurate output. - - Updated default size/position for the first launch without saved settings. - - Updated tests to use a separate .ini file to minimize conflicts. - - Updated Corona API for v2015.2731. - - Updated Corona API processing script to follow Lua guidelines. - - Updated Corona API processing script to handle type inheritance. - - Updated `Save As`/`Open` command to use editor specific extensions instead of all. - - Updated capturing editor information during search to work with selections (#547, #416). - - Updated `Replace` and `Replace All` to take selection into account (#547, #416). - - Updated toolbar icons to fix black color in some images. - - Updated `SetDllDirectory` handling to avoid breaking dlopen with wxwidgets 3.1+ (#260). - - Updated Corona interpreter to avoid caching specified path. - - Updated tests to handle platform-specific tests. - - Updated directory traversing tests to work with smaller directories. - - Updated default file mask to match files without extension (#260). - - Updated tests to use a package instead of the obsolete app method. - - Updated wxwidget path in the build script to use git repository after wxwidgets migration. - - Updated menu shortcuts to avoid conflicts in the `File` menu (#540). - - Updated README with features in 1.20. - -### Fixes - - Fixed showing cursor in search panel fields after file search. - - Fixed reapplying markers after reloading modified file (#419). - - Fixed setting interpreter after launching with non-existing project. - - Fixed showing package errors during project switches (#555). - - Fixed `include` command not checking needed `packages` folders to load from (#555). - - Fixed resetting the default interpreter after selecting a non-existent one. - - Fixed restoring project-specific interpreter when switching projects (#570). - - Fixed restoring project-specific interpreter after relaunch (fixes #570). - - Fixed expanding sub-trees in project directory when set to the disk root on Windows. - - Fixed search navigation after selecting one variable instance (fixes #565). - - Fixed editing fragments in folded text (follow-up to d2ddc96a; #564). - - Fixed editing multiple selections when selection is in folded fragments (fixes #564). - - Fixed copy/paste on Windows when UTF-8 invalid strings end in new line (#260, #556). - - Fixed debugging of Busted scripts (closes #552). - - Fixed skipping editor tabs when clicked in some cases on OSX (closes #546). - - Fixed toolbar size not being adjusted on the very first launch. - -### Incompatibilities - - Changed `Toggle Breakpoint` shortcut from `F9` to `Ctrl/Cmd-F9`. - - Removed `Project | Break` shortcut to avoid conflict with breakpoint navigation. - - Removed `allowinteractivescript` setting as no longer needs to be configurable (#538). - -## v1.20 (Oct 08 2015) - -### Highlights - - Added symbol indexing of project files for project-wide search. - - Added support for `file@symbol` fuzzy search (#385). - - Added processing of `ini` setting relative to the IDE location (#483). - - Improved memory handling for large files. - - Improved application performance and memory usage. - - Improved auto-complete order of results and suggestions for case-sensitive matches. - - Updated Windows launcher to add dpi awareness for high dpi monitors. - - Upgraded Lua 5.3 interpreter to 5.3.1. - - Fixed a memory leak after a search panel is opened. - - Fixed an occasional crash from the filetree on Linux (#425, #464). - - Fixed recursive file traversal to skip directories when mask is specified. - -### Special thanks - - To [riidom](https://github.com/riidom) for German translation update. - - To [Yonaba](https://github.com/Yonaba/) for French translation update. - - To [Leo Bartoloni](https://github.com/bartoleo) for Italian translation update. - - To [Christoph Kubisch](https://github.com/pixeljetstream) for glslc updates. - - To Brigham Toskin for auto-complete improvements. - - To Joergen von Bargen for optimized UTF8 validation. - - To Nick Smith for Marmalade interpreter updates. - -### Improvements - - Added handling of translation messages that require pluralization (#70). - - Added check for non-zero file size before reporting load progress (#530). - - Added switching interpreters by clicking on the interpreter label in the status bar. - - Added handling of editor commands (Copy/Paste/SelectAll/Undo/Redo) in search panel controls. - - Added position to the end-of-file lexer token (closes #529). - - Added reporting when a file can't be removed from a project tree. - - Added explicit initialization for `editor.autoactivate` default setting. - - Added allowing `editor.saveallonrun` with `infervalue` static analyzer (closes #524). - - Added support for `include` command in config files. - - Added document `Close` method (#166). - - Added descriptions for new Lua 5.3 `math.*` and `coroutine.*` functions. - - Added functions new to Lua 5.3 to the list of keywords. - - Added reporting of deserialization failures for saved package data. - - Added collapsing white spaces from names shown in the Outline. - - Added workaround for a memory leak in wxlua after a search panel is opened. - - Added jumping to the current function in the outline (#515). - - Added highlighting current functions for better visibility (#515). - - Added skipping unneded fields from the symbol index to reduce memory usage (#515). - - Added showing position of the current function in the Outline (closes #515). - - Added explicit editor destroy during find and replace to conserve memory. - - Added explicit editor destroy during symbol indexing to conserve memory. - - Added turning jitting on when running under LuaJIT. - - Added `Run to Cursor` to the popup menu in the editor (#413). - - Added showing memory usage stats in the status bar configured by `showmemoryusage`. - - Added skipping opening a file from symbol search when nothing is matched. - - Added skipping directories during directory traversal (#499). - - Added `SetStatusFor` package method to set temporary status (#166). - - Added forcing immediate refresh of symbol index when requested from the menu (#499). - - Added `onMenuOutput` event (#166). - - Added `onMenuWatch` event (#166). - - Added disabling symbol indexing for directories/projects (#499). - - Added refreshing of symbol index to the project menu (#499). - - Added reporting of the number of files queued for indexing (#499). - - Added reporting when indexing is completed (#499). - - Added `GetOutline` package method (#166, #499). - - Added exclusion to not report `arg` as global in static analysis (closes #503). - - Added `commandbar.width` to set the width of command bar. - - Added skipping symbol index queue when symbol inactivity is not set (#499). - - Added setting different types of indentation guides. - - Added optimization with prefiltering for short patterns (#31, #499). - - Added status message during index update (#499). - - Added purging of outdated cache for symbol indexing (#499). - - Added symbol processing of tabs that are not saved yet (#499). - - Added indexing of project files (#499). - - Added `commandbar.maxitems` configuration setting (#499). - - Added caching of symbols for open files (#499). - - Added support for `file.lua@symbol` fuzzy search (#385). - - Added symbol search in all open files (#385). - - Added check to avoid loops in type assignment during auto-complete (#498). - - Added primitive handling of `require` in type assignments for known APIs (fixes #498). - - Added support for aborting file reading callback (#491). - - Added progress display when loading large files (#491). - - Added status methods: `GetStatus`, `PushStatus`, and `PopStatus` (#166). - - Added `onMenuOutline` callback (#166, #337). - - Added ability to toggle outline sorting from the local menu (#337, #494). - - Added activating Output panel after compilation errors. - - Added package `SetStatus` method (#166). - - Added `Ctrl/Cmd-Enter`/`Ctrl/Cmd-Shift-Enter` to add line after/before the current one (#334). - - Added ignoring current selection in auto-complete with `Shift-Enter` (closes #494). - - Added hiding auto-complete after typing one of the offered options (#494). - - Added activating Output notebook to show search results if it's hidden (#416). - - Added reporting of errors when unable to open file for static analysis. - - Added collapsing whitespaces in function parameters in the outline (#337). - - Added emphasis for the preference type in the config file template. - - Added `FileSize` method as the default one returns non-zero result for non-existing files. - - Added reporting of `FileWrite` failing to write the entire content. - - Added package methods `AddIndicator`, `GetIndicator`, and `RemoveIndicator` (#166). - - Added missing `Detach Process` id to keymap (pkulchenko/MobDebug#19). - - Added a check for `ini` setting pointing to a path with a writeable directory (#483). - - Added a check for `ini` setting pointing to a directory (#483). - - Added processing of `ini` setting relative to the IDE location (closes #483). - - Added Watch view refresh after switching focus when needed. - - Added Stack view refresh after switching focus when needed. - - Added forced `Refresh`/`Update` to improve redrawing of commandbar on Windows 8. - - Added a check for a window to be shown to avoid callback recursion on OSX (fixes #473). - - Added package `IsWindowShown` method (#166). - - Added package `onEditorPreClose` event (#166, closes #461). - - Added deleting the rest of the word on auto-complete (`acandtip.droprest`). - - Added closing editor tab when renaming to an open file from the project tree. - - Added refresh of the target file after renaming from the project tree. - - Added a check for object with a focus (occasionally triggered on Linux). - - Added workaround to fix crash on Linux from the project tree (#425, #464). - - Added `DoWhenIdle` package method (#166). - - Disabled unhiding one of wxwidgets windows that is only used for message passing (Windows). - - Disabled initial highlight when showing current function disabled in the outline (#515). - - Disabled dragging out search results tab to avoid unexpected results (#416). - - Enabled compilation during running/debugging (closes #479). - - Enabled static analysis during running/debugging (#479). - - Integrate ZeroBrane with Marmalade's Hub GUI - - Improved auto-complete suggestions for case-sensitive matches. - - Improved compactness of saved package settings (#166, #499). - - Improved performance of saving symbol index data (#499). - - Improved memory usage when closing large files (#491). - - Improved handling of large files (#491). - - Improved the order of results in auto-complete (closes #469). - - glslc tool: add menu option for pre-process mode - - Optimized saving package settings (#166, #499). - - Optimized UTF8 validation (thanks to Joergen von Bargen). - - Optimized handling of multi-line changes in the editor (closes #477). - - Removed forced garbage collection as it led to crashes on Linux (#425, closes #464). - - Revised: auto-complete results (amends #469, w/@pkulchenko patch) - - Switched to the bottom location for the search results by default (#416). - - Updated italian translations (thanks to Leo Bartoloni) - - Updated Russian translation (#70). - - Update de.lua (thanks to riidom) - - Updated french translation as of commit (thanks to Yonaba) - - Updated translation files for new messages (#70). - - Updated translation logic to accept empty tables for pluralization values (#70). - - Updated build scripts to use the most recent releases of LuaJIT and Lua 5.2. - - Updated OSX launcher to keep `DYLD_LIBRARY_PATH` if already set. - - Updated build scripts to use the most recent releases of LuaJIT and Lua 5.2. - - Update marmalade API definition to 7.9 - - Updated static analyzer (luainspect) to take globals in 'required' files into account (#520). - - Updated static analyzer to refresh cache of 'required' modules (#520). - - Updated C/cpp spec to skip `if(...)` from the list of functions. - - Updated C/cpp spec to properly handle functions at the beginning of a file. - - Updated package data serialization to use simpler dumper for faster processing. - - Updated saving symbol index to be called less frequently (#499). - - Updated list of fields to skip from saved symbol index (#499). - - Updated Run/Debug to not force saving new tabs when `Start` file is set. - - Updated interpreter handling to allow setting of default value in the config (closes #518). - - Updated highlighting of the current function in the Outline to select one item (#515). - - Updated auto-complete to close when one of the options matches the current input. - - Updated applying limit to the commandbar results to allow them to be resorted. - - Updated status messages for better visibility on OSX during index refresh (#499). - - Updated tracking of editor updates to skip unneeded notifications on OSX (#499). - - Updated symbol refresh to do processing as soon as the path is known (#499). - - Updated symbol index to skip unused elements in serialization (#499). - - Updated prefiltering to limit prefix to avoid penalty for long `s.*s.*s...` (#31). - - Updated package `SetSettings` method to allow passing of additional parameters (#166). - - Updated status of files indexing for symbol search (#499). - - Updated `DoWhenIdle` handling to gracefully handle a long queue. - - Updated `Go To Symbol` to refresh files loaded in the preview (#499, #385). - - Updated symbol search to only refresh outline when it's not populated (#385). - - Updated search logic to avoid showing search results in recent files (#416). - - Updated line number handling to adjust for large files (#491). - - Updated `busted` interpreter to check for proper extension on Windows (closes #495). - - Updated handling of binary and utf8 validness checks for large files (#491). - - Updated build scripts for Lua 5.3 to use 5.3.1. - - Updated toolbar to show large icons by default on large screens. - - Updated outline to only retrieve entry text when there are tokens to process (#337). - - Updated getting text length without requesting editor content. - - Updated showing function indicator handling to allow for easier enabling. - - Updated indicator processing to use new API. - - Updated ID references in toolbar to use the new access method. - - Updated ID references in keymap to use the new access method. - - Updated `Detach Process` to allow access to it while the process is running. - - Updated metalua/static analyzer to accept long integer and imaginary numbers (closes #482). - - Updated internal parser to accept long integer, imaginary, and floating point hex numbers (#482). - - Updated internal parser to accept numbers that start with a period (#482). - - Updated compilation and static analysis to keep output when running/debugging (#479). - - Updated indentation after strings with brackets and escaped quotes (#324). - - Updated `AnalyzeString` to add filename parameter (closes #463). - - Updated Windows launcher to add dpi awareness for high dpi monitors. - - Upgraded Lua 5.3 interpreter to 5.3.1 on Linux (x86 and x64). - - Upgraded Lua 5.3 interpreter to 5.3.1 on OSX. - - Upgraded Lua 5.3 interpreter to 5.3.1 on Windows (closes #453, closes #460). - - Upgraded Mobdebug (0.628) to include `keyignore` serializer option. - - Upgraded Mobdebug (0.627) to improve debugging of code with overloaded `string` methods. - - Upgraded Mobdebug (0.624) to make `DONE` async and to add `__tostring` protection (closes #446). - -### Fixes - - Fixed text search and fuzzy symbol search in symlinks (#458, #530). - - Fixed opening only one tab for external debugging of dynamic code on Linux (closes #526). - - Fix live picking up debug vs release binaries (Marmalade) - - Fixed highlighting for those specs that don't have information on where functions end (#515). - - Fixed highlighting the current function when anonymous functions are hidden (#515). - - Fixed styling of comments that include markup inside markup (fixes #514). - - Fixed updating symbols in new files that haven't been indexed yet (#499). - - Fixed opening empty files (fixes #510). - - Fixed autocomplete for words that may include underscores in suggestions. - - Fixed crash on OSX during symbol indexing when filetree menu is open (#499). - - Fixed crash on Linux during symbol indexing when filetree menu is open (fixes #507). - - Fixed duplicates between variables and dynamic words in auto-complete. - - Fixed uncommenting of the last line in the selection to keep un/comment reversible (fixes #509). - - Fixed assignment parsing when the type value is re-assigned (#498). - - Fixed mouse selection in auto-complete on OSX (fixes #496). - - Fixed fuzzy file search to not double open already opened files (#31). - - Fixed indentation of lines that end with partial long strings with opening brackets (#324). - - Fixed indentation of lines with long strings that include opening brackets (#324). - - Fixed indicators on table fields after variables that look like multiple assignments (#492). - - Fixed indicators on table fields after variables (fixes #492). - - Fixed variable usage based on static analysis. - - Fixed initial select-and-find search. - - Fixed returning focus to the editor after find-in-files followed by page search (#416). - - Fixed performance of initial fuzzy search for line numbers (closes #476). - - Fixed Output tab name when debugging aborted after run-time error. - - Fixed recursive file traversal to skip directories when mask is specified. - - Fixed crash in `collectgarbage` from the filetree on Linux (#425, #464). - -## v1.10 (May 13 2015) - -### Highlights - - Redesigned search functionality; added incremental search and replace-in-files preview. - - Updated love2d API for v0.9.2. - - Upgraded Mobdebug (0.62) to add vararg processing. - - Added `excludelist`/`binarylist` to exclude files and folders. - - Added skipping binary files during find-in-files and fuzzy search. - -### Special thanks - - To [David Feng](https://github.com/DavidFeng) for fixing a broken symbolic link. - - To [Robert Machmer](https://github.com/rm-code) for updated German translation and fixes for love2d engine name/description. - - To [Derek Bailey](https://github.com/dbaileychess) for adding context menu item to update the contents of the tree. - -### Improvements - - Added closing search results with `Close Page` for consistency (#416). - - Added option to show search results in multipe tabs (#416). - - Added package `IsValidCtrl` method (#166). - - Added skipping binary files in commandbar (#31, #455). - - Added handling of `**` in exclusion masks (#455). - - Added `excludelist`/`binarylist` to exclude files and folders (closes #455). - - Added `search.autohide` option to hide search panel after search (#416). - - Added `debugger.requestattention` to configure focus switch (closes #449). - - Added closing search panel on `Escape` in the editor (closes #450, #416). - - Added `search.zoom` setting to zoom search results (#416). - - Added warning when interpreter can't be loaded and the default one is used. - - Added support for `wxImage` used in `imagemap` (#436). - - Added icon tint processing (`imagetint` option). - - Added `search.contextlinesbefore`/`search.contextlinesafter` settings (#416). - - Added `search.autocomplete` setting do configure search autocomplete (#416). - - Added auto-complete for find and replace fields (#416). - - Added saving search settings between restarts (#416). - - Added deleting of protected text in Cut/Paste operations (closes #412). - - Added refresh context menu item to update the contents of the tree (thanks to Derek Bailey). - - Added ignoring assignment in comments for auto-complete. - - Added preview screen to check changes in replace-in-files (#416). - - Added search toolbar button to set/unset context in search results (#416). - - Allowed for larger default size of docked panels (#424). - - Allowed closing `Search Results` tab while search is in progress (#416). - - Disabled refresh when `outlineinactivity=nil` and `showonefile=true` (#337). - - Improved incremental processing to avoid marking table fields as variables. - - Improved logic to skip binary files during search (#416). - - Moved cancelling auto-complete popup to idle event (fixed #447). - - Moved winapi dll to `clibs` folder to avoid conflict with other winapi versions. - - Optimized `Go To File` file traversal in commandbar (#31). - - Redesigned the search panel (closes #416; closes #398). - - Removed option to request attention from breakpoint activation (#449, closes #454). - - Removed warnings from loose parser to stop polluting stderr on Linux (#425). - - Removed hardcoded references to menu positions to simplify adding new items. - - Removed saving .bak files as it's replaced by replace-in-files preview (#416). - - Reorganized folding to allow more editor-like components to be foldable. - - Switched to using `wxFileSize` instead of `Length` (fixes #458). - - Updated event documentation. - - Upgraded Mobdebug (0.62) to add vararg processing. - - Updated build files to use release version of Lua 5.3 (#453). - - Updated Corona interpreter to allow debugging on Linux using Wine. - - Updated folder traversing logic to limit number of open folders (fixes #441). - - Update Readme.md to use correct name for the LOVE framework (thanks to Robert Machmer). - - Updated Linux build scripts to add `debug` option. - - Updated love2d interpreter to use proper engine name/description (closes #433) (thanks to Robert Machmer). - - Updated german translation (#432, #70). - - Updated love2d APU for v0.9.2 (#247). - - Update german translation (thanks to Robert Machmer). - - Updated `Select and Find` to capture selection for subsequent use (#416). - - Updated `Find Next/Prev` to continue search using the current find text (#416). - - Updated unfolding of folded lines before delete or overwrite. - - Updated folding to collapse only when clicked on the header. - - Updated config samples to use `ID.code` instead of obsolete `G.ID_code`. - -### Fixes - - Fixed crash on Windows by disabling events in Outline refresh (fixes #442). - - Fixed file traversing not to match `foo.bar!` for `*.bar' mask (#416). - - Fixed showing of not translated messages that require pluralization. - - fix broken symbolic link (thanks to David Feng). - - Fixed an empty popup (that could lead to a crash) when dynamic words is on. - - Fixed commandbar positioning on Linux affected by 5b665477 (#31). - - Fixed loose parser to handle multiple assignments (fixes #430). - - Fixed editor activation after dragging of inactive tab (fixes #427). - - Fixed indentation after comment with markdown markup (closes #428, #324). - - Fixed auto-complete issue causing looping warning (#143). - - Fix commandbar position with split editor tabs (#31). - - Fixed re-indenting of selection with comments at the top of the file (#324). - - Fixed restoring pane size after hide/show operations (fixes #424). - -### Incompatibilities - - Removed saving .bak files as it's replaced by replace-in-files preview. - -## v1.00 (Mar 13 2015) - -### Highlights - - Added directory mapping to the project tree (closes #223). - - Added `Run to Cursor` (closes #413). - - Added support to set/unset start file for a project (closes #411). - - Added opening/creating file from the command bar (#31). - - Added `staticanalyzer.infervalue` to enable deeper/slower analysis (#414). - - Updated Corona API for v2015.2576. - -### Improvements - - Added `staticanalyzer.infervalue` to enable deeper/slower analysis (#414). - - Added project path in the error reporting for love2d/corona interpreters. - - Added an example with enabling Emacs bindings in the editor. - - Added Russian translations for new messages (#70). - - Added a warning on class resolution taking too much time in auto-complete. - - Added check for empty/comment lines when breakpoints are set. - - Added directory mapping to the project tree (closes #223). - - Added `Run to Cursor` (closes #413). - - Added document method `GetTabText` (#166). - - Added showing love2d console when requested. - - Added support to set/unset start file for a project (closes #411). - - Added requesting attention for debugger even when the file is not activated. - - Added reporting of location in more cases when debugging is suspended. - - Added starting debugging even when the file is not opened in the IDE. - - Added switching project directory from the command bar (#31). - - Added trimming of trailing spaces in the directory name when switching projects. - - Added closing preview if the file failed to load in commandbar (#31). - - Added handling of `Ctrl/Cmd-Enter` in commandbar to force open file (#31). - - Added skipping loading files with empty and directory names. - - Added trimming of trailing spaces in the file name when loading a file. - - Added file selection in the project tree after saving a new file. - - Added opening/creating file from the command bar (#31). - - Disabled menu item for renaming/editing for mapped directories (#223). - - Disabled field checks for local parameters in staic analyzer (closes #421). - - Improved static analyzer to handle more cases with `infervalue` set (#414). - - Refactored use of image constants in the project tree. - - Refactored document modification tracking to remove `SetDocumentModified`. - - Refactored path normalization for project directory. - - Updated Corona API for v2015.2576. - - Updated static analyzer output formatting. - - Updated analyzer to also check value of `pairs` parameter (#414). - - Updated `debugging suspended` message to not trigger with `runonstart`. - - Updated messages in interpreters to fix line endings. - - Updated lettercase in menu items for consistency. - - Updated UpdateUI handling to fix multi-view refresh, as in DocumentMap (#352). - - Updated Outline to use editor tab text (instead of a file name). - - Updated message on failure to start debugging to add the file name. - - Updated `debugging suspended` message to put location in quotes. - - Updated line check in command bar to not trigger on Windows file names. - - updated glewgl api (glew 1.12.0) - -### Fixes - - Fixed analyzer to check value of `ipairs` parameter (fixes #414). - - Fixed OS detection on Linux that sets `DYLD_LIBRARY_PATH` (fixes #417). - - Fixed saving auto-recovery record with no editor tabs opened (fixes #418). - - Fixed looping in auto-complete when processing recursive assignments. - - Fixed filename used in the recovery message. - - Fixed Output/Console window to stay shown after failure to start debugging. - - Fixed an issue with search initiated from Output/Console panels (fixes #406). - - Fixed auto-complete for non-default `acandtip.strategy` values (fixed #409). - - Fixed loading file with absolute name and line number (fixes #408). - -## v0.95 (Jan 30 2015) - -### Highlights - - Added fuzzy search with `Go To File`, `Go To Symbol`, `Go To Line`, and `Insert Library Function`. - - Added auto-complete support for LDoc '@tparam' and '@param[type=...]'. - - Added armhf architecture support (thanks to Ard van Breemen). - - Updated static analyzer to support `goto`/labels and bitops for Lua 5.2/5.3. - - Updated internal parser to support Lua 5.2/5.3 syntax. - - Updated Mobdebug to improve Lua 5.3 compatibility (thanks to Andrew Starks). - - Update API descriptions with functions new in Lua 5.3. - -### Special thanks - - To [Ard van Breemen](https://github.com/ardje) for armhf architecture support. - - To [Evandro Costa](https://github.com/evandro-costa) for Brazilian Portuguese (pt-br) translation. - - To [Andrew Starks](https://github.com/andrewstarks) for Lua 5.3 compatibility improvements. - - To [Alexis Jarreau](https://github.com/Fringale) for French translation update. - - To [Leo Bartoloni](https://github.com/bartoleo) for Italian translation update. - - To [riidom](https://github.com/riidom) for German translation update. - -### Improvements - - Added showing/hiding Output/Console panel during debugging. - - Added `bordersize` to configure sash size. - - Added package `LoadFile` method (#166). - - Added Russian translation for new messages (#70). - - Added syntax highlighting for functions new in Lua 5.3. - - Added `commandbar.prefilter` to commandbar to improve performance (#31). - - Added custom formatting for APIs. - - Added `Insert Library Function` to `Navigate` menu. - - Added hiding tooltip/auto-complete popup after undo/redo/delete operations. - - Added `api` handling to the config to support custom APIs. - - Added Lapis and Moonscript debugging links to README. - - Added `Contributing` section to README. - - Added LICENSE link to README. - - Added Lua 5.3 links to README; updated links to remove '.html'. - - Added `PgUp` and `PgDn` navigation for commandbar (#31). - - Added auto-complete support for LDoc '@tparam' and '@param[type=...]'. - - Added Brazilian Portuguese (pt-br) translation. - - Added showing the symbol under cursor in `Go To Symbol` (#385). - - Added `editor:ValueFromPosition` method (#166). - - Added `Go To Symbol` support to the commandbar (#31, closes #385). - - Allowed renaming of files with different case in the project tree. - - Added update of file name in the Outline when editor tab is updated (#337). - - Added check for `styles` being reset in the config file (closes #383). - - Added loading file from project directory with "proj file" on command line. - - Added skipping of binary files in commandbar preview (#31). - - Added CONTRIBUTING file. - - Added clearing Output window before showing Find-in-Files results. - - Added default values for Outline config settings (#337). - - Added package `GetProjectNotebook` method (#166). - - Added saving Outline tab configuration in the Project notebook (#337). - - Added `outline.sort` option to sort items in the outline (#337). - - Added `outline.showflat` option to show flat outline (#337). - - Added package `GetOutlineTree` method (#166). - - Add support for armhf architecture - - Added document `Save` method (#166). - - Added `init.lua` to the search path (fixes `require 'dist'`). - - Added forced garbage collection when switching from the app. - - Added penalty for missing characters in fuzzy search (#31). - - Added line navigation to `Navigate` menu (#31). - - Added handling of line numbers in command bar (#31). - - Added caching to improve commandbar performance on large folders (#31). - - Added setting explicit focus on preview tab in commandbar (#31). - - Added preview on first selection in commandbar (#31). - - Added file preview to commandbar (#31). - - Added fuzzy search for files in commandbar (closes #31). - - Added displaying the list of current tabs for commandbar (#31). - - Added commandbar prototype for file navigation (#31). - - Added reset of tokens when editor content is reloaded (#337). - - Enabled html and C/cpp specs by default (#395). - - Improved handling of complex types in LDoc expressions in auto-complete. - - Improved failed search 'shake' visualization by forcing window redraw. - - Improved command line file check for relative files on Windows. - - Split console output into shorter lines to improve memory usage and handling. - - Renamed `debugger.stackmax*` settings to `debugger.maxdata*`. - - Removed double check for invalid UTF-8 output in console. - - Refactored ID handling to allow using `ID.COMMENT` in config files. - - Removed `wxwidgets` from the list of default APIs for Lua interpreters. - - Refactored handling of special symbols in commandbar (#31). - - Removed border from tree controls (#305). - - Updated language files with new messages (#70). - - Update API descriptions with functions new in Lua 5.3. - - Updated loose parser to support Lua 5.2+ labels. - - Updated loose parser to support `goto` and Lua 5.3 bitops. - - Updated Metalua to support Lua 5.3 bitops. - - Updated Metalua to support `goto`/labels in static analysis for Lua 5.2/5.3. - - Upgraded Mobdebug (v0.611) to fix tooltips during Corona debugging (closes #387). - - Updated `CommandBarShow` to accept text fragment to select (#31). - - Updated `GetKnownExtensions` to accept an optional extension to match against. - - Updated `FileRead` to accept optional length. - - Updated layout settings to use constants and new package API. - - Updated parser to avoid splitting `foo.bar` in incremental processing. - - Upgraded MobDebug (0.61) to add `basedir` support. - - Updated status refresh to only happen for the active editor. - - Updated toolbar UI checks to happen when running/debugging (#352). - - Updated Corona integration to hide console on OSX (2014.2393+). - - Upgraded Mobdebug to 0.613 to improve Lua 5.3 compatibility (#401); thanks to @andrewstarks. - - Updated usage instructions in README. - - Update de.lua - -### Incompatibilities - - Renamed `debugger.stackmax*` settings to `debugger.maxdata*`. - - Removed `wxwidgets` from the list of default APIs for Lua interpreters; use `api` config setting to include it. - -### Fixes - - Fixed search navigation to shift horizontally when `usewrap` is off. - - Fixed indentation for lines with mixed string separators (#324, #388). - - Fixed indentation for lines with escaped slashes (#324, closes #388). - - Fixed find-and-replace to replace in already selected fragment if matched. - - Fixed refresh of files in command bar preview when selected (#31). - - Fixed recovery of empty (`untitled`) tabs. - - Fixed an auto-complete issue after `repeat until `. - - Fixed setting focus to the editor in commandbar with one tab (#31). - - Fixed auto-complete after text not separated by a whitespace or bracket. - - Fixed an error when disabling outline by setting `outlineinactivity=nil`. - -## v0.90 (Nov 08 2014) - -### Highlights - - Added function outline. - - Added Lua 5.3 (beta) binaries and debugging support. - - Added scope-aware auto-complete for local/global variables. - - Added hiding/showing files by type in the project/filetree. - - Added Esperanto (eo) translation. - - Improved compatibility with Lua 5.2 interpreter. - - Improved compatibility with system/custom Lua interpreter. - -### Special thanks - - To [cosmotect](https://github.com/cosmotect) for added Esperanto translation. - - To [riidom](https://github.com/riidom) for updated German translation. - - To [Christoph Kubisch](https://github.com/pixeljetstream) for glsl improvements. - - To [Wojciech Milkowski](https://github.com/milkowski) for making indentation guide configurable. - - To [sclark39](https://github.com/sclark39) for adding project dir to find dialog paths. - -### Improvements - - Added Lua 5.3 (beta) support and binaries. - - Added Russian translation for new messages (#70). - - Added `AddPackage` and `RemovePackage` methods (#166). - - Added `CreateBareEditor` package method (#166). - - Added `GetAPI` method for interpreter (#166). - - Added `GetOutputNotebook` package method (#166). - - Added `IsPanelDocked` package method (#166). - - Added `Run` and `Run as Scratchpad` buttons to the toolbar. - - Added `acandtip.maxlength` option for setting the length of a tooltip. - - Added `function` handling to the token processing. - - Added `imagemap` setting to support custom images. - - Added `onEditorCallTip` method (#166). - - Added `showonefile` option for the outline to always show one file (#337). - - Added an Esperanto (eo) translation. - - Added build support for Lua 5.3-alpha and luasocket for Lua 5.3. - - Added check for existing process id before stopping the process. - - Added check for pending data to improve re-starting debugging session. - - Added collapsing outlines for files in inactive tabs (#337). - - Added creating italic font if only the main one is provided. - - Added document `SetActive` method (#166). - - Added drag-and-drop support for the Outline tab (#337). - - Added example of enabling `Opt+Shift+Left/Right` shortcut on OSX. - - Added function outline (closes #337, closes #222). - - Added handling of `~` in launch command path. - - Added hiding/showing files by type in the project/filetree (closes #375). - - Added local/global indicators to function outline (#337). - - Added marking file after showing files in the tree (#375). - - Added navigation based on 'filename:line:pos' in the Output window. - - Added option for not/showing anonymous functions in the outline (#337). - - Added package `AddTool` and `RemoveTool` methods (#166). - - Added package `CreateImageList` method (#166). - - Added package `ExecuteCommand` method (#166). - - Added package `FindTopMenu` method (#166). - - Added package `GetAppName` method and removed hardcoded name references (#166). - - Added package `GetConsole` method (#166). - - Added package `GetKnownExtensions` method (#166). - - Added project dir to find dialog paths; thanks to @sclark39 (closes #358). - - Added rule to enable `Set From Current File` only when available. - - Added scope-aware auto-complete for local/global variables (closes #291). - - Added scrolling to the top of the outline when `showonefile` is set (#337). - - Added sending Corona SDK simulator output to the Output window on Windows. - - Added translation label for `Toggle Bookmark` toolbar icon (#70, #373). - - Added unindent on backspace (controlled by `editor.backspaceunindent`). - - Added view menu for the Outline window (#337). - - bugfix in output callback for commandline tools - - bugfix on extension change save-as, related to new indication handling - - cg/hlsl/glsl refine isfndef capture, mostly to react on GLSL's layout mechanism - - Disabled moving of Output/Console/Project tabs between panels. - - Disabled closing tabs in floating panels. - - Improved `ffitoapi` tool logic when no replacement is made. - - Improved compatibility with Lua 5.2 interpreter (closes #357). - - Improved scroll positioning in the outline after tab changes (#337). - - Improved support for non-lua specs in the outline (#337). - - Minor update to indentation guides handling (#371). - - Moved 'default' search path to be searched first (#357). - - Reduced rate of toolbar UI checks to improve performance (fixes #352). - - Reduced the number of focus changes in the outline (#337). - - Reduced unnecessary editor processing to improve performance (#352). - - Refactored `GetBitmap` package method (#166). - - Refactored `tools` interface to make it easy to add/remove tools. - - Refactored adding editor tab to ensure callbacks have document data. - - Refactored default `fprojdir` and `fworkdir` from the interpreter code. - - Refactored drag-and-drop processing for Project/Output window tabs (#377). - - Refactored panel docking; added `AddPanelDocked` package method (#166). - - Refactored timer usage for consistency. - - Remove function dropdown from the toolbar (#337). - - Removed menu separator from the Tools menu. - - Removed prepending libraries for debugging to LUA_CPATH when custom interpreter is specified. - - Removed reference to `funclist`, which is no longer needed. - - Removed unused image files. - - Renamed `markvars` method used in spec files to `marksymbols`. - - Renamed image files to have names correspond to the content. - - Reorganized default config settings. - - Reorganized token list processing to keep it within the editor. - - Restored removed function in Lua spec (partial revert of 713d0935). - - Switched to using `Is{Input|Error}Available` instead of `stream:CanRead`. - - updated luxinia2 related files - - Update de.lua - - Updated C-based specs to handle function calls without parameters. - - Updated C-based specs to use `marksymbols` to provide outline for C functions. - - Updated Lua 5.3 build scripts. - - Updated `AddPackage` to assign package file name (#166). - - Updated `RemoveMenuItem` to disconnect handlers attached to the main frame (#166). - - Updated `package.config` description to remove reference to Lua 5.2. - - Updated `showanonymous` to a label for anon functions in the outline (#337). - - Updated code based on static analysis suggestions. - - Updated command launch handling to allow output suppression. - - Updated function call indicator to support `isfncall` and `marksymbols`. - - Updated function indicator processing to use ranges. - - Updated handling of extensions to allow more symbols in extensions. - - Updated images in the outline; added `showmethodindicator` option (#337). - - Updated indicator processing to improve performance on large files. - - Updated interpreter processing to run after packages are loaded. - - Updated label for anonymous functions in the outline (#337). - - Updated language files with new messages (#70). - - Updated markup processing to allow for 3+ markup sequences. - - Updated markup processing to support links in non-editor documents. - - Updated messages for to match translations (#70). - - Updated method of collapsing outline to fix crash on OSX (#337, fixes #368). - - Updated outline logic to show on the very first launch (#337). - - Updated outline to always expand functions in the current file (#337). - - Updated outline to show files without functions (#337). - - Updated outline to track filename changes after `Save As` (#337). - - Updated outline to use `AddPackage` method (#337). - - Updated output callback processing not to run when nothing to process. - - Updated package `GetRootPath` to accept file/directory name (#166). - - Updated parser to avoid 'breaking' statements during incremental processing. - - Updated parser to handle `...` in function parameters. - - Updated parser to report function token before parameters (#337). - - Updated parser to store position for not-quite-valid function names. - - Updated processing of function indicators when auto-analyzer is off. - - Updated search/replace to always use the current editor/output/console tab. - - Updated static analizer to accept typedlua parser in addition to metalua. - - Updated tooltip processing to make it more consistent and better use space. - - Updated translation building script to handle non-string parameters (#70). - - Updated un/comment to keep the current selection and caret position (#360). - - Upgraded MobDebug (0.606) for `Detach Process` to correctly close debugging. - - Upgraded Mobdebug (0.607) to fix debugging after `Detach Process` command. - -### Incompatibilities - - Renamed `markvars` method used in spec files to `marksymbols`. - -### Fixes - - Fixed 'slow' mode of static analysis to work with Metalua 0.7.2. - - Fixed `Output` tab name after stopping/completing remote debugging. - - Fixed `Project` label shown untranslated in other languages (#70, #373). - - Fixed `Run` toolbar label not being translated (#70, #373). - - Fixed activation in `tree:FindItem` when new editor tab is opened (#166). - - Fixed an error when dragging Stack/Watch/other tabs between notebooks. - - Fixed an issue with removing first menu item in RemoveMenuItem (#166). - - Fixed an issue with searching in Output and Console windows. - - Fixed column indicator on lines with tabs (fixes #379). - - Fixed disabling Stack/Watch icons in the toolbar. - - Fixed error after using Enter multiple times in `Find in Files` on OSX. - - Fixed file renaming in the filetree after using `SaveAs`. - - Fixed flicker in the outline when auto-complete is shown (#337). - - Fixed focus switch after selecting a function in the outline and editing (#337). - - Fixed handling of remapped image files; improved error reporting. - - Fixed incorrect `binary not` calculation with wxlua and LuaJIT 2.1. - - Fixed index check during tab name update. - - Fixed keeping toolbar status after hiding it. - - Fixed localization in function outline (#337). - - Fixed localization to avoid error in `SaveAs` processing. - - Fixed navigation in function outline when `showonefile` is set (#337). - - Fixed not hiding directories when files without extension are hidden (#375). - - Fixed off-by-one error in function outline position tracking (#337). - - Fixed outline refresh after quick tab switches (#337). - - Fixed refresh of 'background' markers during debugging. - - Fixed replacement when selection doesn't match the text being searched for. - - Fixed search in files/directories with `%` in the name (fixes #369). - - Fixed storing position in `function` handling. - - Fixed stream reading for the Output to only include actually read chars. - - Fixed unused variables and constants based on static analysis. - -## v0.80 (Aug 31 2014) - -### Highlights - - Added support for expanding table elements in Watch window. - - Added editing of values in Watch window. - - Added highlighting all instances of selected text. - - Added replacing all selected instances using a dialog. - - Added saving (one-line) layout for editor tabs. - - Added support for `filename:` and `filename:p` on the command line. - - Added search in Console and Output windows. - - Improved compatibility with Lua 5.2 to run the IDE. - -### Special thanks - - To [Li Jia](https://github.com/tiwb) for fixing remote path map when 'runonstart' option is set. - -### Improvements - - Added default values for `hotexit` and `saveallonrun` settings. - - Added debugger `GetHostName` and `GetPortNumber` methods (#166). - - Added a check for a local shortcut (F2/Del) being enabled before triggering. - - Added refresh of expanded Watch values. - - Added support for expanding table elements in Watch window. - - Added package `AddWatch` method (#166). - - Added `toolbar.iconsize` to configure toolbar icon size. - - Added `run-as-scratchpad` toolbar icon (hidden by default). - - Added `run` toolbar icon (hidden by default). - - Added `find-in-files` toolbar icon (hidden by default). - - Added support for disabling individual icons in the toolbar. - - Added replacing all selected instances using a dialog (closes #342). - - Added highlighting all instances of selected text (closes #344). - - Added `filetree.mousemove` option to disable drag-n-drop (closes #351). - - Added `suspended` to Output panel title when debugger is stopped (closes #350). - - Added a warning when remote console can't evaluate an expression (#350). - - Added handling of `osname` to package dependencies (#166). - - Added `onIdle` event (#166). - - Added `tree:FindItem` method (#166). - - Added package `Yield` method (#166). - - Added ability to set location of `ini` file from config. - - Added ability to load bitmap as toolbar icon. - - Added package `RemoveMenuItem` method (#166). - - Added ability to customize toolbar. - - Added saving (one-line) layout for editor tabs. - - Added centering of the screen after re-indenting and sorting (#337). - - Added local to variable 'activated' in function mapRemotePath - - Added centering of the screen after 'go to definition' and back (#337). - - Added centering of the screen after selection from the function list (#337). - - Added package `onEditorUpdateUI` event (#166). - - Added package `AddPanel` method (#166). - - Added package `GetUIManager` method (#166). - - Added editor `SetupKeywords` method (#166). - - Added document `GetFileExit` method (#166). - - Added `onEditorPainted` event (#166). - - Added support for `name:` and `name:p` on the command line. - - Added error reporting on failure to load file from the command line. - - Added metalua components to MANIFEST (missing in packaging on OSX). - - Added saving auto-recovery record on switching from the application. - - Added `hotexit` option to exit without forcing to save files. - - Added setting of margin properties to support their reordering. - - Added error reporting on failure to delete directory from project tree. - - Added check for shortcut in conflict being enabled before activating (#233). - - Added workaround for missing `GetChildren` call in some wxlua configurations. - - Added unfolding modified lines to avoid leaving hidden lines in the editor. - - Added search in Console and Output windows (closes #313). - - Allowed double-click selection in the Output window (#313). - - Avoided system lib conflict when debugging by using bundled libs (fixes #355). - - Disabled editing on non-root watch elements. - - Disabled smart indentation for multi-line comments and strings (#324). - - Disabled re-indentation of multi-line comments/strings (#324). - - Disabled `Opt+Shift+Left/Right` shortcut as it conflicts with block selection. - - Enabled editing of values in Watch window. - - Enabled `editor.autoreload` by default. - - Improved config handling when `editor` configuration is removed/empty. - - Improved `autotabs` logic when the file starts with indentation. - - Improved auto-complete logic that tracks variable assignments (fixes #343). - - Improved cursor positioning after re-indenting or sorting. - - Improved compatibility with Lua5.2 to run the IDE. - - Increased default project history length to 20. - - Removed check for multiple references in stack values. - - Refactored stack processing to use methods to handle expandable table values. - - Refactored file name generation for compilation and static analysis. - - Removed erroneous message about failure to open '-psn...' file on OSX. - - Renamed all image files to remove cruft from their names. - - Simplified logic for watch processing. - - Switched from using TreeItemData to Lua tables for watch expressions. - - Switched to using tree control for watches. - - Updated copas library to support non-blocking requests using socket.http. - - Updated Stack and Watch views to better stringify keys. - - Updated watch menu to handle item under mouse cursor. - - Updated constants for image lists. - - Updated `FindMenuItem` method to search in the main and specified menus (#166). - - Updated `ide.config` to access wx, wxstc, and os through metatable. - - Updated recent projects/files handling to allow menus to be removed. - - Updated package `FindMenuItem` method (#166). - - Updated `autotabs` to respect `usetabs` when no indentation is present. - - Updated copy/cut to capture one instance when all are the same (closes #345). - - Updated default marker colors for lighter border (#305). - - Updated auto-recovery logic to skip missing files (fixes #323). - -### Fixes - - Fixed disabling auto-recovery on app switching. - - Fixed find-in-files error when used with editor not in focus (fixes #354). - - Fixed package `GetStack` method to return proper control (#166). - - Fixed Watch window background color on some Mint Linux systems. - - Fixed debugging error when `debugger.runonstart` is specified (fixes #348, #341). - - Fixed keybinding for `Ctrl-` working on Linux (fixes #346). - - Fixed localization based on static analysis. - - Fixed remote path map when 'runonstart' option is set. - - Fixed error reporting during Analyze (fixes #340). - - Fixed using image lists for stack/filetree to keep them in memory. - - Fixed indentation when Enter is hit at the middle of a line. - - Fixed formatting of `until` statements (fixes #335). - - Fixed formatting of strings including comments '--' (#335). - - Fixed restoring proper file names for unsaved tabs during auto-recovery. - - Fixed deleting 'dynamic words' when multiple lines are removed. - - Fixed `love.update` description (#247). - - Fixed indentation of strings starting from `endSomething` (#324). - - Fixed use of '%' in replacement for Lua5.2 compatibility (#153, #156, #143). - - Fixed warnings from static analysis. - -## v0.70 (Jun 18 2014) - -### Highlights - - Added support for OpenResty/Nginx, moonscript, and Lapis debugging. - - Added re-indentation of selected fragment or entire file. - - Added line mapping support for debugging Lua-based languages (e.g. moonscript). - - Added `editor.wrapindentmode` and `editor.wrapstartindent` settings. - - Fixed debugger compatibility with Lua 5.2. - - Fixed `F2` shortcut not working in file tree and watch panel. - - Fixed replace-in-files when saving backup copy is turned off. - -### Special thanks - - To [sclark39](https://github.com/sclark39) for `format.apptitle` option to format IDE title. - - To [Christoph Kubisch](https://github.com/pixeljetstream) for glslc improvements. - - To [Yonaba](https://github.com/Yonaba/) for updated French translation. - -### Improvements - - Added support for nginx debugging (Mobdebug 0.564). - - Added support for custom debugger initializer (global or interpreter-based). - - Added line mapping support for debugging Lua-based languages (e.g. moonscript). - - Added support to force local execution in console by prepending `!` (#326). - - Added setting proper `arg[0]` value during debugging (fixes #329). - - Added double click navigation in the Output window for unnamed files. - - Added centering of line after double click in the Output window. - - Added `editor.wrapindentmode` and `editor.wrapstartindent` settings. - - Added a workaround for focus switching between controls on OSX (#89, #327). - - Added assertion to ensure inserted editor is not in the notebook already. - - Added `format.apptitle` option to format IDE title (thanks to @sclark39). - - Added restoring cursor position after sorting/re-indenting. - - Added `onEditorUserlistSelection` event for userlist selection (#166). - - Added `onEditorAction` event for cut/copy/paste actions (#166). - - Added package `GetEditorWithFocus` method (#166). - - Added `editor.extradescent` option for line spacing (#305). - - Added centering of line on page after re-loading file with a known position. - - Added re-indentation of selected fragment or entire file (closes #324). - - Added sorting of the entire file if nothing is selected. - - Added `Edit | Source` sub-menu. - - Added centering line on page after bookmark navigation. - - Added `GetProjectTree`, `GetWatch`, and `GetStack` package calls (#166). - - Added bookmark-toggle toolbar icon (#233). - - Disabled message on failure to read symlinked folder content on Windows. - - Disabled breakpoint toggling when editor is not in focus. - - Disabled changing toolbar color with `auxwindow` as it only works for the dropdown. - - Increase font size for code fragments in markup (#305). - - glslc: change domain detection to be compatible with file.comp.glsl and file.tese - - Removed checks for specific errors in Local/Remote console. - - Removed focus handling workaround for editor tab changes (#89, #327). - - Renamed `menuformatrecentprojects` to `format.menurecentprojects` (#305). - - Removed handling of project dropdown in menu as it's no longer needed (#305). - - Reorganized menu shortcut conflict handling (#233). - - simplified glslc usage (compile and link based on file extensions) - - treat unreal shaders as hlsl - - Updated auto-complete logic to use configured spec separators. - - Updated logic for populating placeholders in dropdown menus. - - Updated french translation (thanks to @Yonaba) - - Updated menu items to stay enabled only when appropriate object has focus. - - Updated indentation logic for if/elseif/while/for split into 2+ lines (#324). - - Updated indentation logic to ignore comments (#324). - - Updated README with supported engines and installation instructions. - - Updated breakpoint-toggle toolbar icon to better match other icons (#305). - - Updated bookmark navigation to wrap around (#233). - - Updating sorting to keep original line endings. - - Upgraded metalua to v0.7.2. - -### Fixes - - Fixed setting control focus when the main frame is hidden. - - Fixed loading packages with dashes in filenames (fixes #330). - - Fixed toolbar to stay shown after failure to start debugging. - - Fixed focus on the editor after closing a dialog on OSX (fixes #328). - - Fixed crash on OSX when changing focus while the app is being closed (#327). - - Fixed some toolbar buttons being enabled with no editor tab open. - - Fixed toolbar stealing focus after closing floating panels and dropdowns (#327). - - Fixed restoring control focus when the app gets focus on OSX (fixes #327). - - Fixed activating editor when starting the app on OSX (#327). - - Fixed auto-complete to not offer the word the cursor is on. - - Fixed hiding auto-complete when the only option matches what's typed. - - Fixed an error when all editor tabs are closed. - - Fixed replace-in-files when saving backup copy is turned off. - - Fixed re-indenting of anonymous functions in tables (#324). - - Fixed `F2` shortcut not working in file tree and watch panel (#233). - - Fixed debugger compatibility with Lua 5.2 (Mobdebug 0.561). - -## v0.60 (May 11 2014) - -### Highlights - - Added support for switching breakpoints at run-time. - - Added bookmark handling. - - Added `Detach process` command to stop debugging and continue process. - - Added detaching debugger server. - - Added showing/hiding toolbar and status bar. - - Simplified user interface and updated application icons. - - Updated love2d API for v0.9.1. - - Updated Moai API for v1.5. - - Added `outputshell.usewrap` to set Output wrapping; on by default. - - Added `editor.wrapflags` to configure line wrapping indicators. - - Added `editor.foldflags`; set default to draw one line when folded. - - Added `editor.foldtype` with box, cirle, arrow, and plus types. - - Added `editor.extraascent` option to add line spacing. - -### Special thanks - - To [bartoleo](https://github.com/bartoleo) for italian translation update. - - To [riidom](https://github.com/riidom) for german translation update. - - To [sclark39](https://github.com/sclark39) for Copy Full Path implementation. - - To [DanielSWolf](https://github.com/DanielSWolf) for Moai API update for v1.5. - - To [madmaxoft](https://github.com/madmaxoft) for AnalyzeString patch. - - To [crumblingstatue](https://github.com/crumblingstatue) for Zoom update. - - To [SiENcE](https://github.com/SiENcE) for notepad++ colorscheme update. - -### Improvements - - Added new italian translations (thanks to @bartoleo) - - Added Russian translation for new messages (#70). - - Adding Copy Full Path to editor tabs, and a Clear Output Window option to the Output tab (thanks to @sclark39) - - Added support for packages in config files (#166). - - Added formatting for Recent Projects menu (#305). - - Added `Detach process` command to stop debugging and continue process. - - Added re/docking of Watch/Stack notebooks on tab background doubleclick (#305). - - Added bookmark handling (closes #233). - - Added `Clear items` to the Recent Files menu (ref #305). - - Added recent files dropdown to the toolbar (ref #305). - - Added applying new UI settings after upgrade (ref #305). - - Added toolbar button dropdown with recent projects (ref #305). - - Added `Choose Project Directory` to the toolbar (ref #305). - - Added floating/docking of notebooks on tab background doubleclick (ref #305). - - Added Recent Project menu refresh after switching projects (ref #305). - - Added setting project directory by renaming the filetree root element (#305). - - Added filetree popup menu with the list of projects (ref #305). - - Added 'Recent Projects' menu (ref #305). - - Added package `GetLaunchedProcess` call (ref #166). - - Added `IsRunning` and `IsConnected` API calls for the debugger (ref #166). - - Added `editor.wrapflags` to configure line wrapping indicators (ref #305). - - Added explicit sorting of files in the filetree. - - Added showing/hiding of the status bar (ref #305). - - Added auto-showing toolbar when debugging starts (ref #305). - - Added showing/hiding of the toolbar (ref #305). - - Added `outputshell.usewrap` to set Output wrapping; on by default (ref #305). - - Added `editor.foldflags`; set default to draw one line when folded (ref #305). - - Added `editor.extraascent` option to add line spacing (ref #305). - - Added explicit conversion to number for numeric settings. - - Added `editor.foldtype` with box, cirle, arrow, and plus types (ref #305). - - Added opening a new tab on double click on tab background (ref #305). - - Added ActivateItem method to the filetree API (ref #166). - - Added onFiletree* package events (ref #166). - - Added setting margin mask to allow for different margin order. - - Added support for switching breakpoints at run-time (closes #288). - - Added stopping debugging when debugger server is detached/stopped. - - Added opening file on one-click in icon/padding area in the filetree. - - Added AnalyzeString function (thanks to @madmaxoft). - - Added zooming for Output/Console windows (ref #290). - - Added IDs for Zoom menu items (ref #290). - - Add zoom actions with appropriate keyboard shortcuts to View menu (thanks to @crumblingstatue) - - Added detaching debugger server. - - Added skipping reporting for known globals in static analysis (closes #286). - - Added support for running zbstudio script from any folder on OSX. - - Adjusted `code` color in the comment markup for better visibility (#305). - - Changed order of stopping debugger and saving settings (ref #305). - - Cleaned unused variables and functions based on static analysis. - - Disallowed closing Output/Console/Project tabs (fixes #310). - - Disabled current project on the recent projects list (ref #305). - - Disable function call indicator by default to reduce clutter (ref #305). - - Disabled startng multiple find-in-files searches. - - Disabled editing/dragging of the project directory in the filetree. - - Enabled editor width auto-adjustment when wrapping is off. - - Enable retina support (`hidpi=true`) by default on OSX (#305). - - Increased default font size in the editor (ref #305). - - Increased wait time for Gideros player to start for more reliable launching. - - Made fold and marker margins wider (ref #305). - - Made jump-to-line in the Output window to work faster and more reliably. - - Moved `Project Directory` menu item lower to not activate on OSX (ref #305). - - Moved code to populate `wx` and `wxstc` descriptions to API files. - - Rearranged global functions in lua spec for simpler grouping (ref #79). - - Reduced sash (border between subsections) in all notebooks (ref #305). - - Reduced the line number margin width and default font size (ref #305). - - Refactored editor config references. - - Removed `Clear Dynamic Words` menu as it's rarely used. - - Removed the gripper on the toolbar (ref #305). - - Removed project selection dropdown from the filetree (ref #305). - - Removed paragraph conversion from love2d API conversion script (ref #247). - - Removed border around Output/Console panels (ref #305). - - Removed deprecated `startfile` interpreter option. - - Removed explicit margin numbers to make configuraton simpler. - - Removed border around editor components. - - Reordered markers to keep the curent line marker on top (#305). - - Reorganized and updated configuration examples. - - Set def linenumber font size as one smaller than editor font size (ref #305). - - Switched to plain background for the toolbar (ref #305). - - Switched to AuiToolBar as it provides buttons with dropdowns (ref #305). - - Upgraded Mobdebug (0.56). - - Upgraded debugger (mobdebug 0.553) to fix an issue with STEP command. - - Upgraded copas to the current version (v1.2.1). - - Updated default fonts for Windows and Linux for better looking ones (#305). - - Update de.lua (thanks to @riidom) - - Updated language files with new messages (#70). - - Updated copyright messages. - - Updated `Go To Line` menu item and its translations. - - Updated build scripts with a fix for a wxlua compilation issue (#260). - - Updated build prerequisites Linux install script. - - Updated default indicator color to more neutral one (#305). - - Updated OSX build script to use 10.7 SDK with 10.6 min-version (#260). - - Updated Mobdebug (0.555) to add support for `pause` debugger call. - - Updated lua interpreter to remove caching of executable path. - - Updated resetting pid only after completing non-debbugged process. - - Updated shortcut for Recent File navigation (ref #305). - - Updated application icons (ref #305). - - Updated stack/watch panel captions to be invisible (ref #305). - - Updated interpreters to check `ProgramFiles` env variable on Windows. - - Updated panel captions to be invisible (rev #305). - - Updated 'window unhide' logic (Windows only) to be called less frequently. - - Updated love2d interpreter to not hide the application window. - - Updated file sorting to be case-insensitive on all platforms. - - Updated filetree menu to use 'Edit Project Directory' on root element (#305). - - Updated love2d API to fix typos in descriptions (ref #247). - - Updated love2d API for v0.9.1 (ref #247). - - Updated love2d API conversion script to handle top-level functions (ref #247). - - Updated `PackageUnRegister` call to return the package on success (ref #166). - - Updated fold/wrap flag handling to work with wxwidgets 2.8 (ref #305). - - Updated breakpoint/currentline markers for less contrast colors (ref #305). - - Updated default folding to use lighter colors (ref #305). - - Updated default colors to have less contrast (ref #305). - - Updated Open file dialog to use current file or project location (closes #303). - - Updated Moai API for v1.5 (thanks to @DanielSWolf). - - Updated `autoanalyzer` option to more common spelling (analizer -> analyzer). - - Updated auto-complete to show in IDLE event for smoother processing. - - -minor color changes to notepad++ colorscheme (thanks to @SiENcE). - -### Incompatibilities - - Added opening a new tab on double click on tab background. - - Added re/docking of Watch/Stack notebooks on tab background doubleclick. - - Enabled retina support (`hidpi=true`) by default on OSX. - - Removed deprecated `startfile` interpreter option; use `startwith` option instead. - - Updated file sorting to be case-insensitive on all platforms. - - Updated `autoanalyzer` option to more common spelling (analizer -> analyzer). - - wxwidgets 2.8 is no longer supported (wxwidgets 2.9.5+ required). - -### Fixes - - Fixed Corona interpreter to clean debugger in `plugin` folder (Win). - - Fixed file tree activation of a deleted file. - - Fixed switching to full screen and restoring status bar on OSX (ref #305). - - Fixed right-click handling in filetree on OSX broken by 3709f61f (ref #166). - - Fixed usage of `self` in one of package API calls (ref #166). - - Fixed find dialog to stay on top after search directory selection on OSX. - - Fixed search result navigation after clicking beyond the end of line. - - Fixed an issue with running processes not terminated when closing IDE. - - Fixed an error after manual canceling Find-in-files dialog. - - Fixed an issue with deleting column-based selection (fixes #300). - - Fixed an error in variable indicator processing. - - Fixed looping when `valuetype` creates self-reference in APIs (ref #297). - - Fixed `elseif` auto-indentation (fixes #294). - - Fixed focus for Find field in the find dialog on some instances of OSX. - -## v0.50 (Mar 10 2014) - -### Highlights - - Fixed opening files and launching on OSX 10.6.x and 10.9.1+. - - Improved CPU utilization when idle on OSX. - - Added handling of command-line parameters. - - Implemented various auto-complete and tooltip improvements. - - Updated Love2d API for 0.9.0. - - Updated Corona API auto-complete/description to match v2014.2189 (G2.0). - - Updated Marmalade Quick API for v7.2. - - Updated French, German, Italian, and Russian translations. - -### Special thanks - - To [Asmageddon](https://github.com/Asmageddon) for fixed launching zbstudio from folders with spaces. - - To [Christoph Kubisch](https://github.com/pixeljetstream) for various luxinia2 fixes. - - To [Yonaba](https://github.com/Yonaba/) for updated French translation. - - To [riidom](https://github.com/riidom/) for updated German translation. - - To [bartoleo](https://github.com/bartoleo/) for updated Italian translations. - -### Improvements - - Added explicit focus for Find field in the find dialog on OSX. - - Added version dependency check for loaded plugins. - - Added `auxwindow` attribute to style auxiliary windows. - - Added sha2 library to provide sha256 hashing. - - Added package GetRootPath/GetPackagePath calls (ref #166). - - Added package FindMenuItem API call (ref #166). - - Added API call to analyze one file. - - Added restoring markers after external modification and file reload. - - Added displaying number of selected characters and instances (closes #274). - - Added using safe load for external data instead of loadstring. - - Added check for editor state during Edit menu display (ref #70). - - added italian translations; thanks to [bartoleo](https://github.com/bartoleo/). - - Added Russian translation for new items in the main menu (ref #70). - - Added package GetApp method (ref #166). - - Added package GetDebugger API call (ref #166). - - Added setting project directory passed as a parameter (second instance). - - Added Shift+Zoom to zoom all editors (closes #269). - - Added `alpha` setting for sel/seladd/caretlinebg styles. - - Added package GetToolBar API call (ref #166). - - Added `seladd` setting for styling additional selections. - - Added `Select and Find Next/Prev` (closes #268). - - Added showing search dialog for Quick Find on first search (closes #265). - - Added `nomousezoom` option for Console/Output windows (closes #266). - - Added error reporting when debugger server fails to start (closes #263). - - Added support for command line parameters for GSL-shell (ref #251). - - Added support for editor shortcuts and included standard OSX ones (closes #252). - - Added auto-complete for metamethods (closes #256). - - Added Minimize shortcut on OSX (closes #254). - - Added handling of command line parameters for love2d (ref #251). - - Added handling of command line parameters (closes #251). - - Added calling of end callback for detached processes. - - Added skipping compile check for non-lua files in scratchpad. - - Added handling of (optional) BOM in UTF-8 encoded files (closes #246). - - Added hint about removing backslash for invalid escape sequences. - - Adjusted tooltip position and content to always fit on the screen. - - allow tool exe paths to be set in config prior load - - Changed the order of applying styles to apply the main style last. - - Disabled singleinstance check by default on OSX (ref #204). - - Disable debugging termination when stack trace received from remote process. - - glsl: added imageSize to spec and api - - luxinia2 define some global vars if debugger is present - - luxinia2 support 32 and 64 bit runtime - - luxinia2: new setup, added support for debugging with main.lua and rudimentary scratchpad functionality - - Reduced the number of inactivity checks and timer calls (ref #204). - - Removed `calltipbg` attribute as it's replaced by `calltip.bg`. - - Removed unused files from metalua. - - Removed paragraph-to-newline conversion for API tooltips. - - Resolved conflict for Opt+Left (ref #252 and #203). - - Removed jumping to the current line after compilation errors. - - Switched to using temp files instead of -e option for debugging (ref #251). - - shader tools: allow relative directories for binaries - - shader specs: add isfncall definition to allow indication style - - Updated AddConfig/RemoveConfig to refresh styles after changes (ref #166). - - Updated Marmalade Quick API for v7.2. - - Updated Corona API for v2014.2189. - - Updated scheme picker to apply styles to all windows. - - Updated LfW interpreter to use project directory as current one (fixes #276). - - Updated README. - - Updated comment markup separators to apply markup in fewer cases. - - Updated French translation; thanks to [Yonaba](https://github.com/Yonaba/). - - Update de.lua; thanks to [riidom](https://github.com/riidom/). - - Updated Linux scripts to remove custom libpng/zlib as it's fixed in wxwidgets. - - Updated check for editor state during Edit menu display (ref #70). - - Updated Corona API auto-complete/description to match v2013.2100 (ref #73). - - Updated all language files with new messages (ref #70). - - Updated messages for better translation (ref #70). - - Updated love2d api with LineJoin and few other calls (ref #247). - - Updated OSX build script for wxwidgets 3.x (ref #260). - - Updated build script to compile wxwidgets 3.x on Windows (ref #260). - - Updated love2d api with some missing calls (ref #247). - - updated luxinia2 interpreter to reflect new luxinia2 structure - - Updated Love2d API for 0.9.0. (closes #247). - - Upgraded Mobdebug (0.551) to fix serialization of table/array indexes. - - updates to shader apis (bugfix in GLSL atomic description) - -### Incompatibilities - - Updated LfW interpreter to use project directory as current one (fixes #276). - - Removed `styles.calltipbg` as it is replaced by `styles.calltip.bg`. - -### Fixes - - Fixed shortcut menu generator to display default shortcuts. - - Fixed removing focus from editor when IDE loses focus on OSX (ref #204). - - Fixed hiding calltip and auto-complete when switching between tabs on OSX. - - Fixed handling of getenv returning general message (Mobdebug v0.5511). - - Fixed launching zbstudio from folders with spaces; thanks to @Asmageddon. - - Fixed `calltip` attribute to use/enable proper style. - - Fixed visibility of wrapped lines in console when going through history. - - Fixed syntax issues in definitions of IDE tables. - - Fixed an issue in metalua files when syntax error is reported. - - Fixed arrow key handling in Local console (fixes #279). - - Fixed removing temporary files in GSL-shell interpreter. - - Fixed tooltip positioning for long messages. - - Fixed current line in debugging after activation of files with wrapped lines. - - Fixed spurious ESC after activation on Windows when modifiers are pressed. - - Fixed skipping empty lines in tooltip formatting. - - Fixed comment markup at the end of a file. - - Fixed formatting calculations for tooltip to better fill the window. - - Fixed stopping debugging when switching projects with the same interpreter. - - Fixed auto-complete for classes with more than two levels. - - Fixed removal of paragraph breaks in tooltips after interpreter switch. - - Fixed API reloading that caused removal of paragraph breaks in tooltips. - - Fixed translations for stock menu items on Ubuntu 13.10 (ref #70). - - Fixed an issue with spec/tools/interpreters filters not working from config. - - Fixed messages script to work with LuaJIT. - - Fixed console output with multiple new lines at the end. - - Fixed issues on OSX 10.6.x and 10.9.1+ caused by flat namespace (fix #270, fix #264). - - Fixed an issue with `isfncall` spec property not being checked. - - Fixed function localization in menu handlers. - - Fixed default selection for search in case of multiple selections. - - Fixed dependency of lfs/git dlls on lualib.dll. - - Fixed an issue with activating proper tab after dragging. - - Fixed displaying local console output with invalid unicode characters. - - Fixed displaying script output with invalid unicode characters. - - Fixed drawing artifacts on Windows when line wrapping disabled (fixes #250). - - Fixed setting bom value for a new editor (fixes #258). - - Fixed auto-complete for values returned by 'core' functions (ref #256). - -## v0.40 (Dec 14 2013) - -### Highlights - - Added LuaDist integration. - - Added live coding support for GSL-shell. - - Added support for project settings. - - Added filetree operations. - - Added Busted interpreter. - -### Special thanks - - To Jayanth Acharya for SciTeLuaIDE color scheme. - - To Mike Richards for adding edge handling and styles. - - To [adamdmoss](https://github.com/adamdmoss) for Mobdebug API update. - -### Improvements - - Added live coding support for GSL-shell (closes #239). - - Added support for product-specific links in the Help menu. - - Added 'edge' style to the color schemes (ref #237). - - Added ability to set 'edge' style properties individually (ref #237). - - Add edge to styles - - Add fold margin checker color to styles - - Add edge line and fold margin checker color - - Added changing directory when launching on Linux (closes #157). - - Added setting PATH for LfW to allow loading of DLL dependencies. - - Added logic to set architecture dynamically for luadist (ref #225). - - Added luadist bootstrap dependencies for Linux (ref #225). - - Added option to load luadist as a module (ref #225). - - Added luadist bootstrap dependencies for OSX (ref #225). - - Added proxy dll for Lua 5.2 (ref #225). - - Added luadist bootstrap dependencies for Windows (ref #225). - - Added package GetInterpreters method (ref #166, #225). - - Added package AddConsoleAlias/RemoveConsoleAlias methods (ref #166, #225). - - Added version property to the Lua interpreters. - - Added new location for Marmalade Quick v7+ and s3e path logic (fixes #226). - - Added directory creation (if needed) to file saving. - - Added support for symlinks in the filetree (with recursion protection). - - Added package AddConfig/RemoveConfig methods (ref #166). - - Added package GetProject method (ref #166). - - Added package onProjectPreLoad method (ref #166). - - Added workaround for conflict with Scintilla shortcuts on Linux. - - Added 'Open with Default Program' to file tree operations (ref #123). - - Added toggling directory on Enter (ref #123). - - Added 'Copy Full Path' to file tree operations (ref #123). - - Added deleting file/directory to file tree operations (ref #123). - - Added processing of packages from `$HOME/.zbstudio/packages` folder (#166). - - Added 'New File' and 'New Directory' to file operations (ref #123). - - Added error reporting for failed rename operations (ref #123). - - Added re-opening editor tabs affected by directory move/rename (ref #123). - - Added package FindDocumentsByPartialPath method (ref #166). - - Added existing file overwrite confirmation when renaming (ref #123). - - Added existing file overwrite confirmation when saving. - - Added creating intermediate directories during file rename (ref #123). - - Added in-place editing of file and folder names (ref #123). - - Added refreshing editor tab after drag-n-drop operation (ref #123). - - Added drag-n-drop operation to move files in the project tree (ref #123). - - Added package AddMarker/RemoveMarker methods (ref #166). - - Added package GetStatusBar method (ref #166). - - Added package GetDocuments and document methods (ref #166). - - Added `EscapeMagic` function to escape magic characters. - - Added SciTeLuaIDE color scheme (thanks to Jayanth Acharya). - - Changed glslc option to reflect new version - - Disabled compilation check for scratchpad when `skipcompile` is set (ref #239). - - Disabled output activation for messages redirected to Console (ref #225). - - Disabled commenting for file types that don't specify line comments. - - Moved restoring project before loading files (ref #107). - - Reorganized loading configuration files (ref #107). - - Removed 'file no longer exists' message after moving opened files (ref #123). - - Removed some of the snippets as they are available as plugins. - - Store os specific clibs path to make it available to plugins. - - Tidy up estrela tools a bit (remove key strokes from cgc, remove luxinia res viewer, rename perforce files to get loaded again) - - Updated README. - - Updated samples with missing indicator constants (closes #243). - - Updated OSX executables and added 'fake' proxy for lua-dist support (ref #225). - - Updated handling of case-insensitive names during debugging on OSX (Mobdebug v0.545). - - Updated package onEditorPreSave to be called on SaveAs events (ref #166). - - Updated icon bundle to eliminate large icons. - - Updated application icon to a bit brighter one on OSX (closes #196). - - Updated build script on OSX to not require 10.6 SDK (closes #231). - - Updated menu definitions for consistency. - - Updated use of `unpack` for consistency and Lua 5.2 compatibility. - - Updated 'Open with Default Program' on Windows to work with spaces in names (#123). - - Updated cmake installation script to install to '/Applications' on OSX. - - Updated OSX build script to revert wxwidgets commit to fix auto-complete crash. - - Updated `Start debugging` hint to clarify. - - Updated single-click toggle to allow rename/move directories (ref #123). - - Updated normalization flags as some path parts were changed to dots. - - Updated editor tab processing using FindDocument method. - - Updated shortcut for Replace All to avoid conflict on OSX (fixes #220). - - Updated `SetDocumentModified` to use current tab text. - -### Fixes - - Fixed values 'captured' by redirected 'print' and not collected (fixes #240). - - Fixed typo in fold style definition (ref #237). - - Fixed console output being limited in addition to stack result limit. - - Fixed hang in auto-complete on expressions involving '...' (fixes #235). - - Fixed auto-complete for string values (broken by 933aacc2). - - Fixed crash when LUA_DEV environmental variable is not set (fixes #228). - - Fixed cmake cache filename (ref #225). - - Fixed incorrect UTF-8 sequence in UTF-8 validity check. - - Fixed Un/Comment menu for Output/Console windows. - - Fixed format of the file name reported after compilation errors. - - Fixed jumping to compilation error (if any) after Run/Debug. - - Fixed disabling 'Open with Default Program' on OSX (ref #123). - - Fixed file tree update after changes on OSX (ref #123). - - Fixed copying full path on OSX (ref #123). - - Fixed 'Open with Default Program' for paths with spaces on Windows (ref #123). - - Fixed folding issue (caused by `math.mod` not available in LuaJIT). - - Fixed debugger marker calculations to avoid marker conflicts. - - Fixed color references in marker config examples. - - Fixed Step Over/Out to stay in the same coroutine; Mobdebug 0.543 (closes #217). - - Fixed case sensitivity in matching of file name in error messages (fixes #216). - - Fixed tab text after SaveAs and loading files into the same tab. - -## v0.39 (Oct 06 2013) - -### Highlights - - Added Lua 5.2 support out of the box. - - Added suggesting dynamic words as fields in auto-complete. - - Added 'go to definition' (Ctrl/Cmd+Alt+Click) and 'jump to previous location' (Alt+Left). - - Added abbreviation of project directories to keep unique parts visible. - - Fixed breakpoints with Marmalade Quick. - - Switched to using LuaJIT interpreter by default. - - Upgraded Luasocket (3.0-rc1), copas, and coxpcall libraries. - -### Special thanks - - To Chow CheeWen for Chinese translation. - - To [Enrique García](https://github.com/kikito) for fixing `fixutf8` function. - - To [Riidom](https://github.com/Riidom) for German translation. - - To [ardente](https://github.com/ardente) for user home patch for Windows and separating Lua 5.1 and 5.2 paths in user config. - - To [Mika Attila](https://github.com/crumblingstatue) for code folding patch. - - To [Tim Mensch](https://github.com/TimMensch) for auto-save, auto-reload, and debugger improvements. - - To [Florian](https://github.com/SiENcE) for Notepad++ color scheme. - - To [Michal Kottman](https://github.com/mkottman) for 'go to definition' and Alt+Left navigation patch. - - To [Christoph Kubisch](https://github.com/CrazyButcher) for dx11 and glslc updates. - - To [jpoag](https://github.com/jpoag) for improved activation during debugging on Windows. - -### Improvements - - Added setting project directory when passed as a parameter. - - Added activation of windows with SDL_app class name (Moai support). - - Added support for joining/splitting Watch/Stack with Output/Console tabs. - - Added package GetSetting method (ref #166). - - Added selected index to package onMenuEditorTab event (ref #166). - - Added activation of windows with FREEGLUT class name (Moai support). - - Added hiding console window for Corona (2013.8.28+) applications (Windows). - - Added suggesting dynamic words as fields in auto-complete. - - Added socket.connect for compatibility with socket.core <3.0 (fixes #208). - - Added recalculating line number margin width after zooming (fixes #207). - - Added margin constants and removed unused variables. - - Added reporting of socket error for initial debugger calls (Mobdebug 0.5403). - - Added error handling/reporting for `debugger.outputfilter`. - - Added 'debug' option to OSX build script. - - Added ability to modify exe path in base interpreter (ref #197). - - Added package GetEditorNotebook method (ref #166). - - Added 'molokai' color scheme (ref #200). - - added hlsl spec and basic api (note: currently autocomplete doesn't work on object functions, need fix). also fixed cg syntax lexer settings - - Added file activation for abbreviated file names in error messages. - - Added abbreviation of project directories to keep unique parts visible. - - Added `debugger.redirect` configuration option. - - Added `editor.saveallonrun` configuration option. - - Added package GetOutput method (ref #166). - - Added package onAppLoad/onAppClose events (ref #166). - - Added package onIdleOnce event (ref #166). - - Added manifest to the Windows executable and re-signed. - - Added Notepad++ color scheme (thanks to Florian/SiENcE; closes #193). - - Added clearing document styles after saving file with a different extension. - - Added workaround to avoid crash on OSX after `Close All Pages` (closes #190). - - Added return type for string.* functions to assist in auto-complete (ref #189). - - Added handling of string literals in type assignments (closes #189). - - Added support for captures in regexp replacement (\1-\9). - - Added ability to cancel FindInFiles search by closing search dialog (ref #162). - - Added activating Output window before showing search results (ref #162). - - Added support for packages from different platforms to co-exist (ref #166). - - Added ability to save complex data in package settings (ref #166). - - Added support for multiple inheritance in auto-complete (ref #101). - - Added ability to add/remove API descriptions from plugins (ref #166). - - Added package GetSettings/SetSettings methods (ref #166). - - Added methods to save/restore package settings (ref #166). - - Added ability to add/remove specs from plugins (ref #166). - - Added ability to add/remove interpreters from plugins (ref #166). - - Added wxlua patch for twoface compatibility. - - Added `setfenv` for Lua 5.2 compatibility. - - Added links to project page and documentation (closes #180). - - Added German translation (thanks to Riidom; ref #70). - - Added default value to package config (ref #176). - - Added handling of ?51.dll and required DLLs for LuaForWindows interpreter. - - Added plugin::GetConfig method (ref #166). - - Added erasing current line in Console (ref #173). - - Added search/completion in the local and remote console (closes #173). - - Added package onAppFocus* events (ref #166; ref #172). - - Added Chinese translation (thanks to Chow CheeWen; ref #70). - - Added `editor.autoreload` to enable reload of updated files (ref #172). - - Added creating (missing) folders when saving a file (fixes #171). - - Added an example of styling individual keywords. - - Added fold indication of a current block (ref #168). - - Added reporting of process id for a conflicting process. - - allow to define separate lua 5.1 and 5.2 paths in user config - - Changed 'go to definition' to Ctrl/Cmd+Alt+Click (ref #203). - - Changed `un/comment` to act from the beginning of the line for multi-line selection. - - Disabled refreshing Watch/Stack windows when they get focus. - - Disabled markup styling for specs without comment styles. - - Disabled showing tooltip when auto-complete suggestions are shown. - - Disabled error reporting after debugging has been terminated. - - Disabled 'Fold' menu instead of removing when no folding is allowed (ref #169). - - dx11 and glslc updates - - Enabled editing watches with doubleclick or Enter. - - Enable Ctrl+Click and Alt+Left navigation on local variables - - Enabled support for xml/html folding. - - Enabled path remapping for local debugging. - - Enabled slower and more thorough static analysis (ref #149; ref #168). - - Improved file/debugger activation on Windows (ref #199). - - Improved IDE activation during debugging on Windows (closes #199); thanks to jpoag. - - Improved logic to jump to file/line indicated in error messages. - - Limited activation of code fragments to the beginning of debugging session. - - Make code folding optional (thanks to [Mika Attila](https://github.com/crumblingstatue)) - - Moved 'Sort' menu to 'Edit'. - - OpenGL 4.4 and ARB extensions added as well as NV_gpu_shader5 functions - - Optimized handling of large tables in stack results. - - Optimized line count calculation for dynamic words when text is deleted. - - Optimized dynamic word processing for large files. - - Reduced CPU usage while idle (ref #204, #206). - - Renamed package onEditorPostSave event to onEditorSave for consistency (ref #166). - - Removed comment from default spec as it forces undesired markup styling. - - Removed auto-complete suggestion when it is already typed (ref #101). - - Reorganized auto-complete handling; should fix #164. - - Reorganized path separator handling to minimize use of global variables. - - Reorganized API processing to allow loading API description from a plugin. - - Replaced package onEditorActivated event with onEditorFocus* events (ref #166). - - Set search in subdirectories as default in Find in Files dialog (ref #162). - - Switched to using POSIX compatible regexp with '()' used for captures. - - Updated LICENSE information. - - Updated Windows build file for wxwidgets 3.0. - - Updated support for MOAI coroutine debugging (Mobdebug 0.541). - - Updated type assignment logic to remove spurious types. - - Updated Windows build script to enable gdb debugging. - - Updated OSX build script to not strip debug builds. - - Updated Corona interpreter to handle failure to copy debugger to Resources/ folder. - - Updated build scripts with proper INSTALL_PREFIX option. - - Updated CFBundleIdentifier in plist files to allow references from OSX programs. - - Updated un/comment to toggle selection as a group rather than line by line. - - Updated `NewFile` to accept a file name. - - Updated 'get hostname' logic to avoid using non-resolvable names (mostly on OSX). - - Updated tooltip to use the same type inference as auto-complete (ref #101). - - Updated Estrela reference in README. - - Updated build script on Windows to enable debugging (ref #164). - - Updated build script with a (temporary) fix for wxlua issue (mingw32). - - updated glewgl api for OpenGL4.4 and removed non-core duplicate functions/enums - - Updated static analyzer to report only first instance of 'unknown field'. - - Updated filename/source code heuristic in the debugger (Mobdebug 0.5362). - - Updated `SaveAll` to allow saving (only) files with filenames (ref #172). - - Upgraded copas and coxpcall libraries (closes #144). - - windows: adopt native user home (thanks to [ardente](https://github.com/ardente)) - -### Fixes - - Fixed Lua 5.2 crash on OSX (added -O1). - - Fixed onInterpreterLoad to only be called when interpreter changes. - - fix the fixutf8 function (thanks to Enrique García). - - Fixed handling of source code fragments in the Stack view. - - Fixed Watch/Stack windows to refresh when shown. - - Fixed incorrect editor tab acted upon in split notebook situations. - - Fixed auto-complete suggestions for indentifiers matching partial function names. - - Fixed hiding launched windows when running/debugging (Windows). - - Fixed showing known functions in auto-complete. - - Fixed showing output with invalid UTF8 characters in Stack and Console windows. - - Fixed debugging on/off handling in 'main' thread for LuaJIT (MobDebug 0.5402). - - Fixed having duplicate tabs after SaveAs with existing file name. - - Fixed showing redirected 'print' messages after debugging is terminated. - - Fixed using default interpreter when no interpreter is selected. - - Fixed stepping through blocks with undefined variables when 'strict' is in effect (upgraded Mobdebug to 0.5401). - - Fixed loading of files with incorrect UTF-8 encoding and control characters (fixes #198). - - Fixed package sample to take into account new documents. - - Fixed crash on OSX after opening 'application' in 'Open File' dialog. - - Fixed windows resource file to properly reference the manifest. - - Fixed missing default api for files with unknown extensions. - - Fix spurious replacement after 'search, clear selection, replace' actions. - - Fixed using auto-complete with multiple selections (fixes #188). - - Fixed looping in auto-complete with array references (ref #143). - - Fixed showing auto-complete after comma. - - Fixed 'cannot get official hostname' message on low privilege accounts (fixes #183). - - Fixed displaying variable instances when code has invalid blocks (fixes #182). - - Fixed tooltip to ignore string parameters (ref #101). - - Fixed tooltip display between empty brackets (ref #101). - - Fixed indentation after lines with brackets in strings. - - Fixed indentation after lines with anonymous functions. - - Fixed indicator showing at the end of not terminated long comment. - - Fixed an issue with LUA_DEV including files instead of directories. - - Fixed project switching to close all files when switching to a subdirectory. - - Fixed saving projects that do not have any open files. - - Fixed debugger to accept filenames without '@'; thanks to Tim Mensch (closes #174). - - Fixed sorting when the sorted fragment ends with a newline. - -## v0.38 (Jun 21 2013) - -### Highlights - - Added source code debugging (to support LuaJava and other engines). - - Added scope-aware global/local/masked/masking variable highlighting. - - Added 'Go To Definition' and 'Rename All Instances'. - - Added package/plugin API. - - Added Retina display support (can be enabled with `hidpi` option). - - Improved auto-complete API with inheritance and table index support. - -### Special thanks - - To George Pimm for line of code navigation in the Stack Window. - - To Fringale for updated French translation. - - To Tom Burgel for LuaForWindows interpreter. - -### Improvements - - Added sorting of file lists on Linux (used in the filetree and file search). - - Added LuaForWindows interpreter (thanks to Tom Burgel). - - Added package onEditorCharAdded/onEditorKeyDown events (ref #166). - - Added support for changing the Corona simulator skin (closes #151). - - Added inheritance support for auto-complete API. - - Added package onEditor* events (closes #166). - - Added package onInterpreterLoad/onInterpreterClose events (ref #166). - - Added package onProjectLoad/onProjectClose events (ref #166). - - Added package onMenu* events (ref #166). - - Added package onRegister/onUnRegister events (ref #166). - - Added 'Show Location' to the Project/Filetree menu. - - Added `hidpi` option to enable HiDPI/Retina display support (closes #160). - - Added breakpoint support for unnamed code fragments. - - Added support for debugging (stepping through) unnamed code fragments. - - Added LuaSec to win32 build script. - - Added package/plugin processing. - - Added support for 'silent' execution of shell commands in markup. - - Added `Find Next/Previous` over selected variable instances (ref #163). - - Added `debugger.allowediting` option to allow editing while debugging. - - Added skiping binary files during file search (ref #162). - - Added yield to update search results during file search (ref #162). - - Added showing default extensions in the file search (ref #162). - - Added support for multiple file extensions in the file search (ref #162). - - Added saving folder to search files in (ref #162). - - Added selecting all instances with a double-click on a variable. - - Added `autoanalizer` option for dynamic static analysis. - - Added 'Go To Definition' and 'Rename All Instances'. - - Added initial support for indicating local/global variables. - - Added showing tooltip in any position over a term and showing 'values' (ref #101). - - Added disabling tooltip when context menu is shown. - - Added 'fixing' path returned by wxDirDialog; may be incorrect in 2.9.x. - - Added constant initialization missing on ArchLinux with wxlua 2.8.12.2 (fixes #155; ref #128). - - Added support for table valuetypes in auto-complete for `foo[index]:` (ref #101). - - Added navigation to the line of code in the Stack Window (thanks to George Pimm; closes #134). - - Added `Show Location` to the editor tab menu. - - Added support for absolute filenames in Markdown links. - - Allowed tab width and indentation to be set independently. - - Allowed closing editor tabs while debugger is running. - - Disabled following symlinks during directory scanning to avoid infinite loops. - - Disabled showing tooltip when the app is in the background (fixes #158). - - Disabled 'value' tooltip over variables that match known function names (ref #101). - - Improved error reporting in interpreters on failures to copy the debugger. - - Improved focus on the debugger when a breakpoint hits on OSX (fixes #141). - - Removed sorting in the Stack view to keep the order of table elements. - - Set default directory for Find in Files opened from a new file (#ref 162). - - Updated configuration example for variable indicators. - - Updated Stack view navigation to use clicked on instead of active item. - - Updated Gideros API/auto-complete reference. - - Updated markup to allow opening files from new buffers ('untitled'). - - Updated build scripts to use luasocket 2.0.3. - - Updated linux build files to use latest zlib/libpng to fix png load on Gentoo. - - Updated 'Find in Files' to start in the project folder by default. - - Updated French translation with latest string changes (mostly for find/replace dialogs). - - Updated Marmalade Quick auto-complete API to use class inheritance. - - Updated Gideros auto-complete API to use class inheritance. - - Upgraded Mobdebug to 0.534 for debugging of source code fragments. - -### Fixes - - Fixed looping in auto-complete when indexes are used (fixes #143). - - Fixed possible duplicate paths in the filetree. - - Fixed missing numerical keys in serialized tables (upgraded Mobdebug to 0.535). - - Fixed styling of markup that can be affected by folded lines. - - Fixed value selection with multiple active selections. - - Fixed style compatibility with wxwidgets 2.8 (ref #128). - - Fixed error reporting by (internal) file operations. - - Fixed styling comments that start with markup symbols. - - Fixed restoring a session with one of the files deleted on disk (fixes #161). - - Fixed reporting variable instances for comment/string fragments. - - Fixed 'Rename Instances' to always reset previous selection. - - Fixed auto-complete error for '%dddd' strings (fixes #156). - - Fixed an issue with showing filenames that include '"?*:<>' on OSX/Linux. - - Fixed current line marker being shown using 'Run as Scratchpad' with 'runonstart' option. - - Fixed looping in auto-complete (fixes #151). - - Fixed incorrect localization that led to an error in 'Save' from tab menu. - -## v0.37 (May 09 2013) - -### Highlights - - Added Marmalade Quick auto-complete support and API documentation. - - Added full Marmalade Quick debugging support (requires Quick 1.1+). - - Improved Find/Replace behavior and functionality. - - Added Recent File history navigation. - - Added Preferences menu to simplify access to system/user settings. - -### Special thanks - - To Samuel Dionne-Riel for wxwidgets 2.8 compatibility updates. - - To Mat Hopwood for assistance with Marmalade Quick integration. - -### Improvements - - Added Preferences menu to simplify access to system/user settings. - - Added Russian translation for Find/Replace dialog and (ref #70). - - Added Russian translation for the Preferences menu (ref #70). - - Added 'shaking' Find/Replace window when text is not found (closes #146). - - Added 'wlua' to the list of recognized Lua extensions. - - Added disabling Recent Files menu if the list is empty. - - Added TomorrowContrast color scheme (thanks to Sergey Lerg). - - Added detaching a child process to avoid crash when exiting during debugging. - - Added Recent File history navigation (closes #66). - - Added Marmalade auto-complete support and API documentation. - - Added processing of `runonstart` when using remote debugging (closes #138). - - Added suggesting proper extension after 'Save/Save As' based on current spec. - - Added translation setup for Find/Replace dialog (closes #133). - - Added `nomousezoom` option to disable zoom with mouse wheel in the editor. - - Added selecting text and Cmd-F shortcut in Find dialog on OSX (ref #127). - - Improved file activation when debugging is started (closes #137). - - Reduced the minimum size of the Output/Console panel. - - Refactored Recent Files history to make it faster and simpler. - - Refactored and optimized directory scanning when loading IDE files. - - Separated settings for function dropdown and project tree fonts (fixes #148). - - Updated documentation about default EOL on OSX (ref #102). - - Updated highlighting in Watch windows to not use editor styles. - - Updated documentation for user settings (ref #113, #55). - - Updated Monokai color scheme to fix current line color. - -### Incompatibilities - - (dev) `FileSysGet` has been replaced with `FileSysGetRecursive` with a different signature. - -### Fixes - - Fixed hiding all panels when switching to Full Screen mode. - - Fixed loading a non-existing file. - - Fixed activation of non-existing files/folders in the Project tree. - - Fixed search results for lines without newline. - - Fixed Find/Replace in folders with Unicode names (fixes #147); improved performance. - - Fixed Un/Comment commands executed for empty lines. - - Fixed fold/unfold for files starting with block/comment. - - Fixed history after activating non-existing file in Recent Files. - - Fixed scrolling to restored cursor position on OSX (when `usewrap` = false). - - Fixed Find/Replace dialog to take Enter on OSX (fixes #140). - - Fixed 'breaking' after executing OUT command that never reaches the target level. - - Fixed stopping at a breakpoint at the initial line when `startwith` option is specified. - - Fixed activation of a file loaded into active tab. - - Fixed incorrect tab activation on OSX after using 'Open File'. - - Fixed editor activation when file is loaded into an existing tab. - - Fixed an error after opening non-existing file from 'Recent Files'. - - Fixed blocking on reading app output without processing other events. - - Fixed an issue with duplicate lines shown in the editor. - - Fixed 'Replace All' to take 'Wrap Around' into account (fixes #132). - - Fixed off-by-one error in searching consecutive matches. - - Fixed 'Quick Find' not working without current selection (fixes #131). - - Fixed looping in auto-complete on mistyped class (fixes #130). - - Fixed compatibility with wx2.8 (thanks to Samuel Dionne-Riel; closes #128). - - Fixed replacement logic in Find/Replace that could replace selected fragment (ref #127). - - Fixed an error caused by allowing multiple Search/Replace windows (fixes #127). - -## v0.361 (Apr 12 2013) - -### Improvements - - Added handling of Ctrl-Home and Ctrl-End on OSX (ref #89). - - Added line copy/cut for Ctrl-C/Ctrl-X with no selection. - - Updated About screen to be more configurable and flexible. - - Updated Russian translation (thanks to toiffel). - -### Fixes - - Fixed launch command for Corona debugging on Windows. - - Fixed 'control' check on OSX that changed with wx2.9.2+ (ref #89). - - Fixed wrong tab activated on OSX after using New file in some cases. - - Fixed cursor not being visible in some cases after file is loaded (ref #116). - -## v0.36 (Apr 08 2013) - -### Highlights - - Added 32bit and 64bit **Linux binaries**. - - Enabled **full debugging for Corona on OSX**. - - Improved **debugger performance**. - - Improved **performance of tab and project switching**. - - Added **multiple selection and multi-cursor editing**. - - Made Stack and Watch windows dockable and toggleable. - -### Special thanks - - To toiffel for build improvements and continuous work on wxwidgets 2.9 and Linux support. - - To Marcel van Herk for testing and feedback on Stack and Watch windows behavior. - - To Leo Bartoloni for Italian translation update. - - To Fringale for updated French translation. - - To neomantra for adding cdata processing in the serializer. - -### Improvements - - Added handling of case-insensitive filenames on OSX. - - Added cdata processing (thanks to neomantra). - - Added universal binaries for luasocket on OSX to allow debugging of 64bit applications (for example, LuaJIT) on OSX. - - Added update of Stack and Watch windows after 'Debugging suspended' message. - - Added toggling for View menu items. - - Added auto-show/hide Stack and Watch windows during debugging (closes #110). - - Added ignoring `-psn...` parameter on OSX when reading file names from command line. - - Added migration of configuration file on Windows (helps #89). - - Added check for different spellings of the same folder in the project tree. - - Added scripts to install build prerequisites on Linux (helps #89). - - Added linux binaries with support for x86 and x64 (helps #89). - - Added window list button to the notepad with editor tabs. - - Added centering of current line during debugging. - - Added multiple selection and multi-cursor editing (wx2.9.5+). - - Added dll proxy to make LfW libraries to work with the IDE. - - Disabled showing 'value' in auto-complete after 'a:' (helps #101). - - Enabled full debugging for Corona on OSX. - - Improved debugging performance. - - Improved performance of tab switching and project tree population. - - Improved handling of upvalues with __tostring method in the Stack window. - - Increased default font size for OSX; set 'Monaco' as default font (helps #89). - - Made stack and watch windows dockable (closes #103). - - Optimized project switching and added notebook freezing where possible (ref #89). - - Reduced flicker in the project tree when a file is opened (ref #89). - - Removed binary libraries not currently used. - - Set 'Courier New' as the default font on Linux (ref #89). - - Switched to 'native' menu on OSX and added 24x24 icons required (helps #89). - - Updated Italian translation (thanks to Leo Bartoloni) - - Updated 'method' type in auto-complete to only allow a:b syntax (closes #101). - - Updated language files (es, it, ru) with new messages (ref #70). - - Updated French translation with latest string changes, fixed a few typos (thanks to Fringale). - - Updated Stack and Watch window to not refresh when not visible. - - Upgraded Mobdebug (0.5222) to add serialization with metamethods and notification on incomplete output (closes #109). - - Updated error messages from loading configuration files. - - Updated Linux binaries to use libpng 1.6 with wxwidgets (helps #89). - - Updated Windows/OSX build files to only build components needed (helps #89). - - Updated windows executable to show properly scaled icons in the Explorer. - - Updated status bar to use no border around fields. - - Updated large icons for "native" toolbar on OSX (helps #89). - - Updated function call indicator to use round box with wxwidgets upgrade (helps #89). - - Updated handling of markdown styles to make it more robust (fixes #59). - - Updated README with Marmalade Quick support and Corona tutorial. - -### Incompatibilities - - Configuration file (.ini) location has changed on Windows. The current file will be copied to the new location. - - The debugger now stops on the next executable line after `.start()` call. - -### Fixes - - Fixed activating files in the project tree on a case insensitive system. - - Fixed the Stack view being partially hidden when the root item is too wide (ref #110). - - Fixed left side of the project panel being hidden when a file is activated (fixes #122). - - Fixed breakpoint not firing on the first executable line in debugging (helps #121). - - Fixed terminating debugging of an empty script. - - Fixed reporting of initial line during debugging. - - Fixed editor tab activation after closing another tab on Linux (ref #89). - - Fixed 'Show tooltip' shortcut not working on Linux (fixes #118; ref #89). - - Fixed cursor position being incorrectly restored (fixes #116; ref #89). - - Fixed a warning about empty project directory in local console. - - Fixed an issue with Enter used to select an item in project dropdown (ref #89). - - Fixed an issue with the Project tree when project and app directories are the same. - - Fixed debugger output not being suppressed on Linux and using wlua. - - Fixed a static analyzer issue with anonymous functions defined in expressions (fixes #3). - -## v0.35 (Feb 10 2013) - -### Highlights - - Added support for **debugging Lua 5.2 scripts**. - - Added support for **cross-platform remote debugging**. - - Added support for starting Gideros **on-device debugging**. - - Added support for live coding, script reloading, and coroutine debugging under LuaJIT. - - Added **Marmalade Quick** support. - - Added **live-coding for Corona** interpreter. - - Added editor tab popup menu with 'Close All', 'Close Other', and other items. - -### Special thanks - - To Roland Yonaba and Fringale for updates to French translation. - - To Fringale for enhanced line-endings handling. - - To toiffel for build improvements, continuous work on wxwidgets 2.9 support, and several patches. - - To Andy Bower for the stream of feedback on live coding and on-device debugging. - -### Improvements - - Added `debugger.runonstart` option to configure if debugging should run immediately after starting. - - Added `editor.checkeol` option to configure checking for eol encoding in loaded files. - - Added Marmalade Quick support. - - Added support for starting Gideros on-device debugging. - - Added requesting user attention when stopped during debugging. - - Added example for `defaulteol` configuration option. - - Added configuration option for compact folding (`editor.`). - - Added support for cross-platform remote debugging. - - Added support for script reloading and coroutine debugging under LuaJIT (MobDebug 0.514). - - Added Russian translation for new messages. - - Added handling of malformed UTF8 characters in files (fixes #97). - - Added support for debugging Lua 5.2 scripts. - - Added workaround for Moai require path issue (fixes #96; fixes #87). - - Added editor tab popup menu with 'Close All', 'Close Other', and other items. - - Added C/CPP specification file and a configuration example. - - Added XCode-like key mapping. - - Added removing of file: prefix and url decoding of filepaths (helps #89). - - Added a workaround for returning incorrect project folder (helps #89). - - Adjusted handling of filepath to work with relative and absolute paths (helps #89). - - Enabled live-coding for Corona interpreter. - - Improved line-endings handling (Fringale). - - Improved reporting of stack and serialization run-time errors. - - Updated Gideros interpreter to run debugging immediately after starting; Use `debugger.runonstart = false` to disable. - - Updated Linux startup script to use online versions of wxlua packages (deb files). - - Updated handling of file: prefix as it's different on Windows and OSX (helps #89). - - Updated messages in the starter script. - - Updated function call parsing to recognize "func{}" and "func''" syntax. - - Updated os.exit() call in local console to exit gracefully. - - Updated French translation with various fixes and tweaks (Fringale). - - Updated French translation with newly added strings (Fringale). - - Updated 'Close page' and its translations. - - Updated configuration examples and documentation (helps #55). - - Updated the size of the function list dropdown on Windows (helps #89). - - Typos fixes, small changes in French translation (Roland Yonaba). - -### Incompatibilities - - Gideros debugging is changed to start immediately; use `debugger.runonstart = false` to disable. - - Removed mosync support from the debugger into a separate module. - - Added mixed end-of-line reporting; use `editor.checkeol = false` to disable. - - Added reporting of malformed UTF-8. - -### Fixes - - Fixed a rare crash on OSX when closing IDE with an application running under debugger. - - Fixed path handling for metalua to avoid conflicts with other modules that may include lexer.lua file. - - Fixed executing commands in the Remote console immediately after `mobdebug.start()` (closes #100). - - Fixed invalid escape sequence that fails under LuaJIT. - - Fixed an issue with spec files when a separator (sep) is not specified. - -## v0.34 (Dec 12 2012) - -### Highlights - - Added **internationalization** support (with Russian, Italian, Spanish, and French translations). - - Added **key binding** configuration for menu and toolbar items. - - Added **Corona SDK integration** with debugging and auto-complete. - - Added **Moai scratchpad support**. - - Added **color scheme support** with several schemes included. - - Added **GSL-shell support**. - - Added ability to pause and resume scratchpad. - -### Special thanks - - To Srdjan Markovic for Corona auto-complete support and Zenburn color scheme. - - To Roland Yonaba for French translation. - - To Leo Bartoloni for Italian translation. - - To Inigo Sola for Spanish translation. - - To toiffel for Russian translation and several patches. - - To Fringale for spec and API files cleanup and update for Lua 5.2. - - To Marcel van Herk for assistance with scratchpad break/resume functionality. - -### Improvements - - Added an option to specify the width of the calltip. - - Added showing short descriptions in tooltip for functions without lib/package. - - Added 'Project Directory' menu. - - Added ability to pause scratchpad when the script is completed (closes #83). - - Added ability to pause and resume scratchpad. - - Added GSL-shell support (closes #72). - - Added more color schemes (Solarized and Monokai). - - Added customized yield function for debugging (MobDebug v0.508; closes #81). - - Added proper hiding of current line marker during debugging (except when tracing). - - Added Corona auto-complete support (thanks to Srdjan Markovic). - - Added logic to show application windows without explicitly listing their class (closes #80); Windows only. - - Added Moai scratchpad support. - - Added missing constants to Moai API. - - Added setting focus on the window when a file is loaded in the existing instance. - - Added two more wxwindow window classes to the list of windows to show (Windows). - - Added scheme picker script to test color schemes from the IDE. - - Added Zenburn as a color scheme. - - Added styling for markers and Output/Console windows. - - Added Italian translation (thanks to Leo Bartoloni). - - Added Spanish translation (thanks to Inigo Sola). - - Added reporting of run-time errors from remote processes (helps #73). - - Added 'tomorrow' color theme. - - Added redirect of remote 'print' commands for Gideros applications. - - Added check for 'main.lua' in Corona projects. - - Added ability to suspend a running application even when there is no editor tab or file to activate. - - Added serialization of remote 'print' results and an output filter for debugging (helps #73). - - Added redirect of remote 'print' commands to the Output window in the IDE (helps #73). - - Added Corona SDK support (closes #73). - - Added French translation (thanks to Roland Yonaba). - - Added (more) verbose output to debugger to assist in troubleshooting. - - Added handling of LUA_DEV to make loading Lua for Windows libraries working out of the box (fixes #71). - - Added internationalization support (closes #70). - - Added notes about estrela being gone and compatibility. - - Added multi-tab support for scratchpad. - - Added documentation on accelerator/shortcut syntax. - - Added key map to change key binding for menu and toolbar items from a config file (closes #64). - - Added hiding IDE while closing and saving configuration. - - Completed reorganization of front-end processing (closes #67 and #5). - - Disabled editor autoactivation during debugging when tracing is on. - - Disabled functions that are not available under Corona on OSX (helps #73). - - Disabled showing auto-complete when the only option is already typed. - - Disabled showing a calltip on mouse over when it's already active. - - Extended list of default folders for interpreters where executables are searched for. - - Finished Russian translation. - - Limited auto-showing windows to Lua interpreter only (related to #80). - - Removed window types from config as they are no longer needed to be listed. - - Switched to showing short tooltips by default as some of the updated Lua API descriptions are very long. - - Updated descriptions for io.* functions; moved file:* functions to a pseudo library (f); helps #84. - - Updated LICENSE to add remdebug license information. - - Updated tooltip to show shortened descriptions on mouse-over. - - Updated spec and API files for Lua 5.2 (thanks to Fringale). - - Updated MobDebug to v0.507 to fix serialization issues (closes #77). - - Updated style processing to support styling of markup and allow dynamic switching of color schemes. - - Updated Lua keyword definitions to improve grouping for styling (closes #79). - - Updated love2d api to an updated version as of 11/1/2012 (fixes #78). - -### Incompatibilities - - The default port in the debugger has been changed from 8171 to 8172 to avoid conflicts with existing RemDebug implementations. - -### Fixes - - Fixed an issue with overlapping auto-complete suggestions. - - Fixed auto-complete not working after closed brackets. - - Fixed tooltip being shown when mouse moving outside of the editor area. - - Fixed a font zooming bug with Ctrl+MouseWheel. - - Fixed file marking in the project tree after opening a new file. - - Fixed an issue with breakpoints not available after aborting tracing on Linux/OSX. - - Fixed an issue with running scratchpad when entry points are configured. - - Fixed Linux launcher to pass filename parameter to the IDE. - - Fixed fold style to properly set background color. - - Fixed an issue with a config file being loaded into the editor when specified in the command line. - - Fixed an issue with markdown formatting not working after setting styles from a config file (fixes #74). - -## v0.33 (Oct 22 2012) - -### Highlights - - Added **Linux support**. - - Added **Moai auto-complete**. - - Added **Gideros debugging, auto-complete, and live coding**. - - Added **syntax aware indentation**. - - Added **re/storing open files and interpreter** when switching project folders. - -### Special thanks - - To Andy Bower and Atilim Cetin for their assistance with Gideros integration and live coding. - - To toiffel for Linux/OSX/Windows CMake-based launcher build. - - To [Christoph Kubisch](https://github.com/CrazyButcher) for help with Estrela merge. - -### Improvements - - Added configuration option to specify hostname when the default one is not reachable (fixes #68). - - Added search for Moai and Love2d executables in default locations on OSX and Windows. - - Added handling of command line parameters on OSX and Linux; updated documentation. - - Added auto-recovery to save/restore editor content (fixes #23). - - Added syntax aware indentation. - - Added re/storing open files and interpreter when switching project folders. - - Added auto-activation of files requested during debugging. - - Added editor.autoactivate parameter (false by default) to enable activation. - - Added zbstudio.sh script to run on OSX/Linux; updated permissions (closes #15). - - Added variable ratio for sliders in scratchpad. - - Added Linux/OSX/Windows CMake-based launcher build (thanks to toiffel). - - Added configuration parameter for the number of characters typed before displaying auto-complete suggestions for dynamic words. - - Added proper closing of the application after Shutdown/Logoff events (fixes #57). - - Added Moai auto-complete (closes #52). - - Added hiding auto-complete suggestions on losing focus in the editor. - - Added proper reporting of errors in the stack window. - - Added wxlua.deb file and install script that pull and build all required dependencies on Linux (covers most of #15). - - Added osx executables and build files. - - Added disabling full screen mode when the last editor tab is closed. - - Added proper reporting of errors in config files. - - Added toggling folders in project pane by single click (fixes #41). - - Added examples for configuring tabs and moai entry points. - - Added reporting compilation success rate (fixes #39) - - Added shortcuts for adding and removing watches. - - Added highlighting rows with updated values in the Watch window. - - Added 'Add Watch Expression' and 'Evaluate in Console' context menu items in the editor. - - Added handling of canceling editing in adding a watch. - - Added Gideros auto-complete and live coding support (closes #62). - - Added Gideros integration on OSX; added search for gideros in default locations on Windows and OSX. - - Added Gideros integration and debugging support. - - Added debugging-related buttons to the toolbar. - - Improved reporting of compilation and run-time errors when running as scratchpad. - - Made debugger strict.lua and LuaJIT friendly (upgraded to MobDebug v0.502). - - Updated configuration example to avoid using ide.spec that is not available (fixes #67). - - Updated CMake build script to handle wildcards in the MANIFEST. - - Updated configuring toolbar size to improve Linux compatibility. - - Updated MobDebug to v0.497 to fix issues and improve performance. - - Updated a warning message about single instance communication. - - Updated cpath processing to allow Linux version to run side-by-side with Windows and Mac. - - Updated licensing information. - - Enabled scratchpad support in the debugger when interpreter is capable of providing it. - - Disabled auto-complete in comments and strings. - - Disabled toggling breakpoints while debugger is running (as they wouldn't be changed anyway). - - Disabled 'not activated file for debugging' message when auto-activation is disabled. - - Disabled tooltip when scratchpad is on (fixes #51). - - Disabled showing calltip when the editor is not in focus. - - Disabled showing calltip over markup in comments. - - Disabled 'Run as Scratchpad' in the menu for those intepreters that don't support scratchpad. - - Updated configuration examples to add editor settings and fix user.lua path. - - Moved all Estrela features into a separate bundle that can be loaded using cfg/estrela.lua config. - - Removed multiple file types offered in Save As dialog. - -### Incompatibilities - - Changed searching for user config in '$HOME/.zbstudio' from '$HOME/.zbs'. - - Temporarily removed the ability to modify spec-related configuration parameters from configuration files. - -### Fixes - - Fixed opening a non-existing file from the Recent Files list. - - Fixed Find/Replace dialog checkboxes that didn't react to clicks on OSX (fixes #63). - - Fixed an auto-complete issue with mixed case dynamic words (fixes #60). - - Fixed 'Trying to solve a NULL hostname' warning message. - - Fixed a typo that prevented a corner case in autocomplete from working. - - Fixed inconsistent error messages about various config files. - - Fixed an issue with auto-complete when dot or colon is used (fixes #56). - - Fixed an issue with debugging scripts started using absolute file path. - - Fixed setting working directory for interpreters to the file path when the project directory is not set. - - Fixed an issue with Backspace not closing auto-complete suggestions. - - Fixed enabling items in the Edit menu (fixes #56). - - Fixed function list in the toolbar on Mac (helps #14). - - Fixed deleting of comment blocks with hidden markup (fixes #40). - - Fixed an issue with function list when all editor tabs are closed. - - Fixed multiple calltips shown on Linux (helps #15). - - Fixed an issue with mouse cursor in scratchpad not properly updated on Linux (fixes #49; helps #15). - - Fixed an issue with static analyzer that failes on function names like a.b.c (fixes #50). - - Fixed disabling Paste menu on Linux when needed (fixes #46; helps #15). - - Fixed an issue with context menu on Linux (fixes #47; helps #15). - - Fixed debugger failure when debugging is initiated externally and there is an unsaved file in one of editor tabs. - - Fixed stopping the debugger when an editor tab where debugging happens is closed. - - Fixed enabling of several menu items with no editor tab (fixes #42). - - Fixed an issue with loading stock icons on Linux. - - Fixed Cut/Copy menu items to reflect proper status in the editor. - - Fixed typo in the static analyzer output. - - Resolved conflict between lua executable names on Windows and Mac. - -## v0.32 (Sep 03 2012) - -### Highlights - - Added **Unicode support** for file encoding and file paths on Windows (fixes #30). - - Added **Moai integration and debugging** (including debugging of Moai threads and callbacks). - - Added refresh of Stack and Watch windows after executing a statement in remote shell. - - Added **display of complex values** on multiple lines in shell with '='. - - Added calltip on mouseover for functions during editing and for variables/expressions during debugging. - - Added configuration options to set paths to lua and love2d executables. - - Added support for **coroutine debugging** with stepping through coroutine.resume/.yield calls. - - Updated wx.dll to wxlua 2.8.12.2 and wxwidgets 2.8.12. - - Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25). - -### Improvements - - Added calltip on mouseover for functions during editing and for variables/expressions during debugging. - - Added an IO filter to fix an issue with 0d0d0a line endings on Windows. - - Added support for debugging moai callbacks (upgraded to mobdebug v0.489). - - Added refresh of Stack and Watch windows to show updated values after executing a statement in remote shell. - - Added display of complex values on multiple lines in shell with '='. - - Added rockspec to the list of extensions for lua (fixes #37). - - Added a check to avoid evaluating keywords in tooltip. - - Added current interpreter to the status bar; adding closing debugger when the interpreter is changed. - - Added aborting scratchpad processing when an interpreter can't start or report a fatal error. - - Added support for unicode path files on Windows (fixes #30). - - Added an option to set path to lua executable. - - Added error handler to trap and display debugger errors. - - Added search in PATH for love2d executable. - - Added a workaround for GetExecutablePath() reporting 'wx.dll' instead of a proper exe name with wxlua 2.8.12.2 on Windows. - - Added reporting of function name of the form a.b and a:b in static analysis (fixes #27). - - Added ability for user to keep their settings file in their home directory. - - Added per user settings file. Users can now move their settings file to ~/.zbs/user.lua. - - Added ignoring Cmd-key combinations on Mac as this should be handled by wxwidgets, but is not (fixes #19). - - Added support for coroutine debugging with stepping through coroutine.resume/.yield calls. - - Changed reporting of program execution time from CPU time to user time. - - Changed the call to unhide windows to the async version (ShowWindowAsync) to avoid blocking the IDE when the application doesn't respond. - - Upgraded to wxlua 2.8.12.2 (wxwidgets 2.8.12; unicode version); added lua51.dll proxy (fixes #10 and #7). - - Updated love2d interpreter to use the project folder to check for main.lua. - - Updated test module to use stringified values for comparison. - - Updated status bar style to make it consistent across platforms. - - Removed .bak files from being replaced in when backup copies are saved. - - Removed explicit path conversions and comparisons. - - Refactored LUA_PATH/CPATH processing to set it for all interpreters. - - Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25). - -### Incompatibilities - - Reassigned hotkeys in the Project menu to minimize conflicts on Mac (reassigned Shift-F12 and F11). - -### Fixes - - Fixed an issue with double click on analylsis results being out-of-sync when the editor switched to another file (fixes #38) - - Fixed an issue with debugger not activating files with relative path information. - - Fixed 'break' command to work after coming from debugger calls (like on()). - - Fixed an issue with highlighting selected item in the project tree. - - Fixed evaluation of foo:bar in tooltip (now evaluates as foo.bar). - - Fixed debugger termination after internal errors. - - Fixed activating current file in the project tree on Mac (closes #29). - - Fixed running scripts with single quotes in path names. - - Fixed an issue with Run/Debug commands when IDE path includes exclamation mark ('!'). - - Fixed an issue with the app not starting on those systems that don't have HOME environment variable; fixes #28. - - Fixed an issue with showing/hiding GUI windows that was occasionally causing a runtime error when the window disappears before it is manipulated. - - Fixed returning proper name for unsaved files in reporting compilation and static analysis results; moved default names to ide.config (fixes #26). - - Fixed pasting text into the Find dialog and project path box on Mac (fixes #22). - - Fixed handling of dashes in paths (upgraded to mobdebug 0.479). - - Reorganized handling of automcomplete event (to use AddPendingEvent instead of PostEvent) to avoid runtime application error. - -## v0.31 (Jul 14 2012) - -### Highlights - - Added **scratchpad support for love2d**. - - Added tooltip to display variable/expression values during debugging. - - Added **MacOS support**. - -### Improvements - - Added handling of balanced brackets in markup links. - - Added unit test module. - - Added reporting the number of traced lines during debugging. - - Added setting of PATH and CPATH to find proper libs on windows and mac os platforms. - - Added scratchpad support for love2d. - - Added reset of 'modified' status to keep tab names and their config settings correct upon exit. - - Added window title update and filetree refresh after SaveAs command. - - Added tooltip to display variable/expression values during debugging. - - Made 'View Stack Window' and 'View Watch Window' refresh window content if it's already shown. - - Removed setting the editor font in the config as the default font is different on different platforms. - - Removed extension from the template to match folders to make it more portable. - - Reorganized handling of font configuration and added font config for filetree (with a different size default on MacOS). - - Updated matching logic for function definitions to allow for a.b.c() definitions (fixes #17). - -### Fixes - - Fixed markup styling and file tree drawing on MacOS. - - Fixed detecting executable name in commands with spaces. - - Fixed incorrect folders reported in the file tree when no project directory is set and a file is open. - - Fixed incorrect filename reported in compile errors when the file is not saved. - - Fixed refresh of filetree on MacOS to get it displayed correctly when the app is started. - - Fixed an error thrown when a window with debugging is closed before the application being debugged is terminated. - - Fixed incorrect storing of settings for editor tabs with the same text (filename). This was causing only one tab displayed for multiple StyledText controls with interesting effects. - - Fixed an issue with launching a process when its output is not redirected to the IDE (fixes #16). - - Fixed console to evaluate 'function a() ... end' without errors. - - Fixed a compilation error caused by shebang in scripts. - - Fixed an issue with love2d path with spaces. - - Corrected resetting of project directory when it's already set and doesn't need to be changed. - - Added checks around ShowFullScreen() calls to avoid failures on those systems that don't provide it (linux/GTK). - - Added check for debugger calls to avoid errors when debugger is not loaded. - - Updated matching of links to make them less greedy (to avoid capturing link terminators). - - Upgraded deprecated constants and logic for compatibility with wxwidgets 2.9.x. - - Reset project directory if the current one doesn't exist. - - Removed styling of function calls and capturing definitions in strings and comments (fixed #18). - - Removed setting focus to the Output window when output is processed as it interfered with Run as Scratchpad. - -## v0.30 (Jun 27 2012) - -### Highlights - - Added **love2d support**. - - Added auto complete for love2d API. - - Added support for debugging processes running under LuaJIT. - - Added display of **hierarchical data in Stack window**. - - Added **pretty printing in Watch and Console** (local and remote) windows and handling of multiple results in Console. - - Added **Stack window to display stack information** and local/upvalue values for each stack frame. - - Added ability to **interact with scripts** by allowing text to be entered in the 'Output' window. - -### Improvements - - Added love2d support. - - Added auto complete for love2d API. - - Added support for debugging processes running under LuaJIT. - - Added display of hierarchical data in Stack window. - - Added execution time and updated messages in the Output window to be more consistent. - - Added displaying 'nil' values in local console when no result is returned by an expression. - - Added a check to refuse starting a new debugging session if there is one in progress already. - - Added handling of tail calls in the Stack window. - - Added pretty printing in Watch and Console (local and remote) windows and handling of multiple results in Console. - - Added Stack window to display stack information and local/upvalue values for each stack frame. - - Added ability to set font encoding in the config. - - Added restoring cursor position when a modified file is reloaded in the editor. - - Added ability to interact with scripts by allowing text to be entered in the 'Output' window. - - Improved logic in love2d integration to distinguish Debug and Run commands (closes #13). - - Improved reporting in static analysis for functions and global variables. - - Updated menus to avoid conflicts with MacOS shortcuts. - - Updated logic creating menubar to make it work correctly on MacOS with special Help/About items. - - Updated path handling to better detect how the app is started and to avoid loading dlls on non-windows platforms. - - Updated logic for detecting hostname (used in the debugger) to make sure it is resolvable. - - Changed order of lualibs/ and bin/ directories in package.path and package.cpath to load included modules first. - - Removed extensions from launch commands and updated display logic in the Output window. - -### Fixes - - Fixed aborting running/debugged programs on MacOS by adding MAKE_GROUP_LEADER option to wxExecute. - - Fixed an issue in the logic for setting breakpoints, which ignored breakpoints in luxinia2 debug sessions. - - Fixed logic in the local/remote console that returned incorrect error message on executing code like '%s':format(1). - - Fixed IDs for Project menu items to allow them to be removed from the menu if needed. - - Fixed an issue with remote application not terminating when IDE is closed while debugging is in progress. - - Fixed refreshing a modified file when the editor is set to read-only mode. - - Fixed saving/restoring configuration of 'Output'/'Console' tabs when IDE is closed while debugging is in progress. - - Fixed removing variable name in Watch window after escaping editing. - - Fixed #9 as it had incorrect logic in one of UTF filters. - - Fixed edit menu shortcuts to work in the 'Output' window (when allowed). - - Fixed reporting of processes that failed to start after 'Run' or 'Debug' commands. - - Fixed executable path matching to work on systems that don't have file extensions. - - Fixed #3 'unused parameter...' check not to fail on anonymous functions that are part of an expression. - - Moved processing of `user.lua` to a later phase after tools and specs are already loaded to allow modification of IDE configuration from `user.lua`. Closes #5. - - Added checks to prevent text modification in 'Output' and 'Console' windows. Fixes #8. - - Disabled 'Run as Scratchpad' if there is no debugger registered capable of running it. - - Disabled Stack and Watch updates when scratchpad is active as they interfere with application execution. - -## v0.29 (May 31 2012) - -### Highlights - - Added **scratchpad** (running live) functionality. - - Added **code analyzer** based on lua-inspect. - - Updated **comment styling** to follow markdown syntax. - -### Improvements - - Added scratchpad (running live) functionality. - - Added code analyzer based on lua-inspect. - - Added Ctrl(-Shift)-TAB navigation between tabs in the editor. - - Added navigation between editor tabs using Ctrl-PgUp and Ctrl-PgDn. - - Added reporting of assignment to global variables in the code analyzer. - - Added ability to turn external processes that connect to debugger into a scratchpad. - - Added exit from full screen mode using ESC key. - - Added reporting of compilation errors during debugging sessions. - - Added handling of more errors in the shell to allow calculations like '(1+2)' to be executed correctly. - - Added moving focus back to the notebook after unhiding/activating a wx window. - - Added missing mime/code.dll and reorganized socket module files (socket.*) to load correctly with require. - - Added stopping the debugger when a debugged program exits. - - Added to static analysis reporting of unused parameters in functions. - - Disabled warning in static analysis about unused 'self' in methods. - - Removed 'error during pre-compilation' message from compile errors. - - Updated comment styling to follow markdown syntax. - -### Fixes - - Fixed handling of scripts with comments in the remote shell. - - Fixed an issue with Analyze process when the analyzed script has compilation errors. - - Fixed an issue with scratchpad being on after Save dialog is canceled. - - Fixed about screen. - -## v0.28 (Mar 21 2012) - -### Highlights - - Added full screen mode. - -### Improvements - - Added option to activate output/console when Run/Debug/Compile commands are executed. - - Added full screen mode. - - Added killing a running process on IDE exit. - - Added killing a running process with Shift-F12. - - Disabled buffering of the output for scripts run from IDE. - -### Fixes - - Fixed 'Trace' command to continue working when a debugged file is not activated. - - Fixed an issue with saving a file when no project directory is set. - - Fixed missing semicolon in lualibs path; added path for debugger to search under lualibs. - - Fixed an issue with a missing path separator, which prevented debugging from executing step commands in some cases. - - Fixed missing slash on SaveAs by enforcing trailing slash for the project path. - -## v0.27 (Feb 14 2012) - -### Highlights - - Added markup formatting in the comments. - -### Improvements - - Added markup formatting in the comments. - - Added Debug and Run methods to simulate menu commands. - - Added setting a project folder on initial start. - - Added style processing for font name, font size, visibility and hotspot attributes. - - Added setting the current project directory for the shell to allow 'require' commands to work with local modules. - - Updated markup processing with run and debug commands, http link processing, and opening local files in a new window. - - Enforced visibility for shell prompt. - -### Fixes - - Fixed activation of a correct tab when one of the editor tabs is closed. - - Fixed an issue with file activation from a debugger. - - Fixed the issue of ClosePage method being called with two different parameters. - - Fixed the issue of the project dir being returned with two trailing slashes. - - Fixed an issue with activating the currenly edited file in the file tree. - - Wrapped DragAcceptFiles into a protected call to make it not fail on MacOS (compiled with wxwidgets 2.8.12). - -## v0.26 (Jan 18 2012) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/LICENSE b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/LICENSE deleted file mode 100644 index d05f7d2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/LICENSE +++ /dev/null @@ -1,237 +0,0 @@ ---[[ ZeroBrane Studio License ]]------------------------------------------- - -ZeroBrane Studio sources are released under the MIT License - -Copyright (c) 2011-2015 Paul Kulchenko (paul@kulchenko.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---[[ Estrela Editor License ]]--------------------------------------------- - -Estrela Editor sources are released under the MIT License - -Copyright (c) 2008-2012 - Luxinia DevTeam: - Christoph Kubisch & Eike Decker - info at luxinia.de - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---[[ wxLua License ]]------------------------------------------------------ - -http://wxlua.sourceforge.net/ - -Pre-Built binaries for wxLua/WxWindows - -Original wxLua Lua sample IDE: - Lomtick Software - J. Winwood & John Labenski - luascript at thersgb.net - -wxLua is based on -wxWindows Library License, Version 3 - -Copyright (c) 1998 Julian Smart, Robert Roebling et al - -Everyone is permitted to copy and distribute verbatim copies -of this licence document, but changing it is not allowed. - -WXWINDOWS LIBRARY LICENCE -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -This library is free software; you can redistribute it and/or modify it -under the terms of the GNU Library General Public Licence as published by -the Free Software Foundation; either version 2 of the Licence, or (at -your option) any later version. - -This library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library -General Public Licence for more details. - -You should have received a copy of the GNU Library General Public Licence -along with this software, usually in a file named COPYING.LIB. If not, -write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, -Boston, MA 02111-1307 USA. - -EXCEPTION NOTICE - -1. As a special exception, the copyright holders of this library give -permission for additional uses of the text contained in this release of -the library as licenced under the wxWindows Library Licence, applying -either version 3 of the Licence, or (at your option) any later version of -the Licence as published by the copyright holders of version 3 of the -Licence document. - -2. The exception is that you may use, copy, link, modify and distribute -under the user's own terms, binary object code versions of works based -on the Library. - -3. If you copy code from files distributed under the terms of the GNU -General Public Licence or the GNU Library General Public Licence into a -copy of this library, as this licence permits, the exception does not -apply to the code that you add in this way. To avoid misleading anyone as -to the status of such modified files, you must delete this exception -notice from such code and/or adjust the licensing conditions notice -accordingly. - -4. If you write modifications of your own for this library, it is your -choice whether to permit this exception to apply to your modifications. -If you do not wish that, you must delete the exception notice from such -code and/or adjust the licensing conditions notice accordingly. - ---[[ Lua License ]]-------------------------------------------------------- - -Copyright: © 1994-2006 Lua.org, PUC-Rio. -Homepage: http://www.lua.org -License: http://www.lua.org/copyright.html - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---[[ LuaSockets License ]]------------------------------------------------- - -Copyright: © 2004-2006 Diego Nehab. All rights reserved. -Homepage: http://www.cs.princeton.edu/~diego/professional/luasocket/ -License: http://www.lua.org/copyright.html (same as LUA) - ---[[ Serpent License ]]---------------------------------------------------- - -Copyright (c) 2011-2013 Paul Kulchenko (paul@kulchenko.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---[[ LuaJIT License ]]----------------------------------------------------- - -Copyright © 2005-2013 Mike Pall, released under the MIT open source license. - ---[[ WinAPI License ]]----------------------------------------------------- - -Copyright (C) 2011 Steve Donovan. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---[[ MobDebug License ]]--------------------------------------------------- - -MobDebug sources are released under the MIT License - -Copyright (c) 2011-2012 Paul Kulchenko (paul@kulchenko.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---[[ RemDebug License ]]--------------------------------------------------- - -Copyright (c) 2006 The Kepler Project. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/README.md b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/README.md deleted file mode 100644 index 4b40527..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# Project Description - -[ZeroBrane Studio](http://studio.zerobrane.com/) is a lightweight cross-platform Lua IDE with code completion, -syntax highlighting, remote debugger, code analyzer, live coding, -and debugging support for several Lua engines -([Lua 5.1](http://studio.zerobrane.com/doc-lua-debugging), -[Lua 5.2](http://studio.zerobrane.com/doc-lua52-debugging), -[Lua 5.3](http://studio.zerobrane.com/doc-lua53-debugging), -[LuaJIT](http://studio.zerobrane.com/doc-luajit-debugging), -[LÖVE](http://notebook.kulchenko.com/zerobrane/love2d-debugging), -[Moai](http://notebook.kulchenko.com/zerobrane/moai-debugging-with-zerobrane-studio), -[Gideros](http://notebook.kulchenko.com/zerobrane/gideros-debugging-with-zerobrane-studio-ide), -[Corona](http://notebook.kulchenko.com/zerobrane/debugging-and-live-coding-with-corona-sdk-applications-and-zerobrane-studio), -[Marmalade Quick](http://notebook.kulchenko.com/zerobrane/marmalade-quick-debugging-with-zerobrane-studio), -[Cocos2d-x](http://notebook.kulchenko.com/zerobrane/cocos2d-x-simulator-and-on-device-debugging-with-zerobrane-studio), -[OpenResty/Nginx](http://notebook.kulchenko.com/zerobrane/debugging-openresty-nginx-lua-scripts-with-zerobrane-studio), -[Torch7](http://notebook.kulchenko.com/zerobrane/torch-debugging-with-zerobrane-studio), -[Redis](http://notebook.kulchenko.com/zerobrane/redis-lua-debugging-with-zerobrane-studio), -[GSL-shell](http://notebook.kulchenko.com/zerobrane/gsl-shell-debugging-with-zerobrane-studio), -[Adobe Lightroom](http://notebook.kulchenko.com/zerobrane/debugging-lightroom-plugins-zerobrane-studio-ide), -[Lapis](http://notebook.kulchenko.com/zerobrane/lapis-debugging-with-zerobrane-studio), -[Moonscript](http://notebook.kulchenko.com/zerobrane/moonscript-debugging-with-zerobrane-studio), -and others). It originated from the [Estrela Editor](http://www.luxinia.de/index.php/Estrela/). - -![ZeroBrane Studio debugger screenshot](http://studio.zerobrane.com/images/debugging.png) - -## Features - -* Written in Lua, so easily customizable. -* Small, portable, and cross-platform (Windows, Mac OSX, and Linux). -* Auto-completion for functions, keywords, and custom APIs. -* Interactive console to directly test code snippets with local and remote execution. -* Integrated debugger with local and [remote debugging](http://studio.zerobrane.com/doc-remote-debugging) -for [Lua 5.1](http://studio.zerobrane.com/doc-lua-debugging), -[Lua 5.2](http://studio.zerobrane.com/doc-lua52-debugging), -[Lua 5.3](http://studio.zerobrane.com/doc-lua53-debugging), -[LuaJIT](http://studio.zerobrane.com/doc-luajit-debugging), -and [other Lua engines](http://studio.zerobrane.com/documentation#debugging). -* [Live coding](http://studio.zerobrane.com/documentation#live_coding) -with [Lua](http://notebook.kulchenko.com/zerobrane/live-coding-in-lua-bret-victor-style), -[LÖVE](http://notebook.kulchenko.com/zerobrane/live-coding-with-love), -[Gideros](http://notebook.kulchenko.com/zerobrane/gideros-live-coding-with-zerobrane-studio-ide), -[Moai](http://notebook.kulchenko.com/zerobrane/live-coding-with-moai-and-zerobrane-studio), -[Corona SDK](http://notebook.kulchenko.com/zerobrane/debugging-and-live-coding-with-corona-sdk-applications-and-zerobrane-studio), -GSL-shell, and other engines. -* Function outline. -* Fuzzy search with `Go To File`, project-wide `Go To Symbol`, and `Insert Library Function`. -* Several ways to extend the current functionality: - - specs (`spec/`): specifications for file syntax, lexer, and keywords; - - apis (`api/`): descriptions for [code completion and tooltips](http://studio.zerobrane.com/doc-api-auto-complete); - - interpreters (`interpreters/`): components for setting debugging and run-time project environment; - - packages (`packages/`): [plugins](http://studio.zerobrane.com/doc-plugin) that provide additional functionality; - - config (`cfg/`): settings for styles, color themes, and other preferences; - - translations (`cfg/i18n/`): [translations](http://studio.zerobrane.com/doc-translation) of the menus and messages to other languages; - - tools (`tools/`): additional tools. - -## Documentation - -* A [short and simple overview](http://studio.zerobrane.com/doc-getting-started) for those who are new to this development environment. -* A list of [frequently asked questions](http://studio.zerobrane.com/doc-faq) about the IDE. -* [Tutorials and demos](http://studio.zerobrane.com/tutorials) that cover debugging and live coding for different environments. -* [Tips and tricks](http://studio.zerobrane.com/doc-tips-and-tricks). - -## Installation - -ZeroBrane Studio can be installed into and run from any folder. -No compilation is needed, although the scripts to compile required libraries for Windows, OSX, and Linux platforms are available in the `build/` folder. - -## Usage - -``` -Open file(s): - zbstudio [option] [] [...] - non-options are treated as a project directory to set or a file to open - -Set project directory: - zbstudio [...] - (0.39+) a directory passed as a parameter will be set as the project directory - -Override default configuration: - zbstudio -cfg "" [] - e.g.: zbstudio -cfg "editor.fontsize=12" somefile.lua - -Load custom configuration: - zbstudio -cfg path/file.lua [] - e.g.: zbstudio -cfg cfg/estrela.lua -``` - -If you are loading a file, you can also request the cursor to be set on a particular line or at a particular position by using `filename:` and `filename:p` syntax (0.71+). - -## Contributing - -See [CONTRIBUTING](CONTRIBUTING.md). - -## Author - -### ZeroBrane Studio and MobDebug - - **ZeroBrane LLC:** Paul Kulchenko (paul@kulchenko.com) - -### Estrela Editor - - **Luxinia Dev:** Christoph Kubisch (crazybutcher@luxinia.de) - -## Where is Estrela? - -The Estrela project has been merged into ZeroBrane Studio. If you have used Estrela -for graphics shader authoring or luxinia, create/modify the `cfg/user.lua` and -add `include "estrela"` (1.21+) to load all tools and specifications by default again. - -## License - -See [LICENSE](LICENSE). diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/cg/stdlib.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/cg/stdlib.lua deleted file mode 100644 index ac20661..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/cg/stdlib.lua +++ /dev/null @@ -1,205 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local function fn (description) - local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())") - if not description2 then - return {type="function",description=description, - returns="(?)"} - end - return {type="function",description=description2, - returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args} -end - -local function val (description) - return {type="value",description = description} -end --- docs -local api = { -abs = fn "returns absolute value of scalars and vectors. - (typeN)(typeN)", -acos = fn "returns arccosine of scalars and vectors. - (typeN)(typeN)", -all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)", -any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)", -asin = fn "returns arcsine of scalars and vectors. - (typeN)(typeN)", -atan = fn "returns arctangent of scalars and vectors. - (typeN)(typeN)", -atan2 = fn "returns the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0. - (typeN)(typeN y, typeN x)", -ceil = fn "returns smallest integer not less than a scalar or each vector component. - (typeN)(typeN)", -clamp = fn "returns x clamped to the range [a,b]. - (typeN)(typeN x, a, b)", -clip = fn "conditionally (<0) kill a pixel before output. - ()(typeN)", -cos = fn "returns cosine of scalars and vectors. - (typeN)(typeN)", -cosh = fn "returns hyperbolic cosine of scalars and vectors. - (typeN)(typeN)", -cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)", -ddx = fn "returns approximate partial derivative with respect to window-space X. - (typeN)(typeN)", -ddy = fn "returns approximate partial derivative with respect to window-space Y. - (typeN)(typeN)", -degrees = fn "converts values of scalars and vectors from radians to degrees. - (typeN)(typeN)", -determinant = fn "returns the scalar determinant of a square matrix. - (float)(floatNxN)", -distance = fn "return the Euclidean distance between two points. - (typeN)(typeN a, b)", -dot = fn "returns the scalar dot product of two vectors. - (type)(typeN a, b)", -exp = fn "returns the base-e exponential of scalars and vectors. - (typeN)(typeN)", -exp2 = fn "returns the base-2 exponential of scalars and vectors. - (typeN)(typeN)", -faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (typeN)(typeN Nperturbated, Incident, Ngeometric)", -floatToIntBits = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (intN)(floatN)", -floatToRawIntBits = fn "returns the raw 32-bit integer representation of an IEEE 754 floating-point scalar or vector. - (intN)(floatN)", -floor = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)", -fmod = fn "returns the remainder of x/y with the same sign as x. - (typeN)(typeN x, y)", -frac = fn "returns the fractional portion of a scalar or each vector component. - (typeN)(typeN)", -frexp = fn "splits scalars and vectors into normalized fraction and a power of 2. - (typeN)(typeN x, out typeN e)", -fwidth = fn "returns sum of approximate window-space partial derivatives magnitudes. - (typeN)(typeN)", -intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)", -isfinite = fn "test whether or not a scalar or each vector component is a finite value. - (boolN)(typeN)", -isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(typeN)", -isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(typeN)", -ldexp = fn "returns x times 2 rained to n. - (typeN)(typeN a, n)", -length = fn "return scalar Euclidean length of a vector. - (type)(typeN)", -lerp = fn "lerp - returns linear interpolation of two scalars or vectors based on a weight. - (typeN)(typeN a, b, weight)", -lit = fn "computes lighting coefficients for ambient(x), diffuse(y), and specular(z) lighting contributions (w=1). - (type4)(type NdotL, NdotH, specshiny)", -log = fn "returns the natural logarithm of scalars and vectors. - (typeN)(typeN)", -log10 = fn "returns the base-10 logarithm of scalars and vectors. - (typeN)(typeN)", -log2 = fn "returns the base-2 logarithm of scalars and vectors. - (typeN)(typeN)", -max = fn "returns the maximum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)", -min = fn "returns the minimum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)", -mul = fn "Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B. - (typeN)(typeNxN/typeN a, typeN/typeNxN b)", -normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (typeN)(typeN)", -pow = fn "returns x to the y-th power of scalars and vectors. - (typeN)(typeN x, y)", -radians = fn "converts values of scalars and vectors from degrees to radians. - (typeN)(typeN)", -reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (typeN)(typeN incidence, normal)", -refract = fn "computes a refraction vector. - (typeN)(typeN incidence, normal, type eta)", -round = fn "returns the rounded value of scalars or vectors. - (typeN)(typeN a)", -rsqrt = fn "returns reciprocal square root of scalars and vectors. 1/sqrt. - (typeN)(typeN)", -saturate = fn "returns x saturated to the range [0,1]. - (typeN)(typeN)", -sign = fn "returns sign (1 or -1) of scalar or each vector component. - (typeN)(typeN)", -sin = fn "returns sine of scalars and vectors. - (typeN)(typeN)", -sincos = fn "returns sine of scalars and vectors. - ()(typeN x, out typeN sin, out typeN cos)", -sinh = fn "returns hyperbolic sine of scalars and vectors. - (typeN)(typeN)", -sqrt = fn "returns square root of scalars and vectors. - (typeN)(typeN)", -step = fn "implement a step function returning either zero or one (a <= b). - (typeN)(typeN a, b)", -tan = fn "returns tangent of scalars and vectors. - (typeN)(typeN)", -tanh = fn "returns hyperbolic tangent of scalars and vectors. - (typeN)(typeN)", -transpose = fn "returns transpose matrix of a matrix. - (typeRxC)(typeCxR)", -trunc = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)", - -tex1D = fn "performs a texture lookup in a given 1D sampler and, in some cases, a shadow comparison (as .y coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1D, float/float2 s, |float dx, dy|,[int texeloffset])", -tex1Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])", -tex1Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .y, bias as .w). - (float4)(sampler1D, float4 s, [int texeloffset])", -tex1Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler1D, float4 s, [int texeloffset])", -tex1Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler1D, int4 s, [int texeloffset])", -tex1Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])", -tex1Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .y for float3 coord, proj in .y or .z) - (float4)(sampler1D, float2/float3 s, [int texeloff])", -tex1Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)", - -tex2D = fn "performs a texture lookup in a given 2D sampler and, in some cases, a shadow comparison (as .z coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2D, float2/float3 s, |float2 dx, dy|,[int texeloffset])", -tex2Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2D, float4 s, [int texeloffset])", -tex2Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .z, bias as .w). - (float4)(sampler2D, float4 s, [int texeloffset])", -tex2Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler2D, float4 s, [int texeloffset])", -tex2Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2D, int4 s, [int texeloffset])", -tex2Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2D, float4 s, [int texeloffset])", -tex2Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler2D, float3/float4 s, [int texeloff])", -tex2Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)", -tex2Dgather = fn "returns 4 texels of a given single channel texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)", - -tex3D = fn "performs a texture lookup in a given 3D sampler. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler3D, float3 s, {float3 dx, dy},[int texeloffset])", -tex3Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler3D, float4 s, [int texeloffset])", -tex3Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler3D, int4 s, [int texeloffset])", -tex3Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler3D, float4 s, [int texeloffset])", -tex3Dproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(sampler3D, float4 s, [int texeloff])", -tex3Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler3D, int lod)", - -texBUF = fn "performs an unfiltered texture lookup in a given texture buffer sampler. (only gp4 profiles) - (float4)(samplerBUF, int s)", -texBUFsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerBUF, int lod)", - -texRBUF = fn "performs a multi-sampled texture lookup in a renderbuffer. (only gp4 profiles) - (float4)(samplerRBUF, int2 s, int sample)", -texRBUFsize = fn "returns the size of a given renderbuffer. (only gp4 profiles) - (int2)(samplerBUF)", - -texCUBE = fn "performs a texture lookup in a given CUBE sampler and, in some cases, a shadow comparison (float4 coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBE, float3/float4 s, |float3 dx, dy|)", -texCUBEbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])", -texCUBElod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])", -texCUBEproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(samplerCUBE, float4 s)", -texCUBEsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)", - -texRECT = fn "performs a texture lookup in a given RECT sampler and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerRECT, float2/float3 s, |float2 dx, dy|, [int texeloff])", -texRECTbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(samplerRECT, float4 s, [int texeloffset])", -texRECTfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(samplerRECT, int4 s, [int texeloffset])", -texRECTlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(samplerRECT, float4 s, [int texeloffset])", -texRECTproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(samplerRECT, float3/float4 s, [int texeloff])", -texRECTsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerRECT, int lod)", - -tex1DARRAY = fn "performs a texture lookup in a given 1D sampler array and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1DARRAY, float2/float3 s, {float dx, dy},[int texeloffset])", -tex1DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])", -tex1DARRAYcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (layer as .y, compare as .z, bias as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])", -tex1DARRAYcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .z, lod as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])", -tex1DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .z). - (float4)(sampler1DARRAY, int3 s, [int texeloffset])", -tex1DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .z) - (float4)(sampler1DARRAY, float3 s, [int texeloffset])", -tex1DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler1DARRAY, float3/float4 s, [int texeloff])", -tex1DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1DARRAY, int lod)", - -tex2DARRAY = fn "performs a texture lookup in a given 2D sampler array and, in some cases, a shadow comparison (as .w coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2DARRAY, float3/float4 s, {float2 dx, dy},[int texeloffset])", -tex2DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2DARRAY, float4 s, [int texeloffset])", -tex2DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2DARRAY, int4 s, [int texeloffset])", -tex2DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2DARRAY, float4 s, [int texeloffset])", -tex2DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (proj in .w) - (float4)(sampler2DARRAY, float4 s, [int texeloff])", -tex2DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2DARRAY, int lod)", - -texCUBEARRAY = fn "performs a texture lookup in a given CUBE sampler array. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBEARRAY, float4 s, {float3 dx, dy},[int texeloffset])", -texCUBEARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerCUBEARRAY, int lod)", - -unpack_4ubyte = fn "interprets the single float as 4 normalized unsigned bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)", -pack_4ubyte = fn "packs the floats into a single storing as normalized unsigned bytes.(only nv/gp4 profiles) - (float)(float4)", -unpack_4byte = fn "interprets the single float as 4 normalized signed bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)", -pack_4ubyte = fn "packs the floats into a single storing as normalized signed bytes.(only nv/gp4 profiles) - (float)(float4)", -unpack_4ushort = fn "interprets the single float as 2 normalized unsigned shorts and returns the vector. (only nv/gp4 profiles) - (float2)(float)", -pack_4ushort = fn "packs the floats into a single storing as normalized unsigned shorts.(only nv/gp4 profiles) - (float)(float2)", -unpack_2half = fn "interprets the single float as 2 16-bit floats and returns the vector. (only nv/gp4 profiles) - (float2)(float)", -pack_2half = fn "packs the floats into a single storing as 16-bit floats.(only nv/gp4 profiles) - (float)(float2)", -} - -local keyw = -[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4 -float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4 -float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4 -double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4 -int4 bool bool2 bool3 bool4 string struct typedef -usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY -isampler isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY -usamplerBUF isamplerBUF samplerBUF -sampler sampler1D sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY -texture texture1D texture2D texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY - -decl do else extern false for if in inline inout out pass -pixelshader return shared static string technique true -uniform vector vertexshader void volatile while - -asm compile const auto break case catch char class const_cast continue default delete -dynamic_cast enum explicit friend goto long mutable namespace new operator private protected -public register reinterpret_case short signed sizeof static_cast switch template this throw -try typename union unsigned using virtual - -POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG COLOR COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 -TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14 -TEXCOORD15 -NORMAL WPOS -ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5 ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15 -TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9 TEXUNIT10 TEXUNIT11 TEXUNIT12 -TEXUNIT13 TEXUNIT14 TEXUNIT15 - -PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX -PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX -VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX -VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX -WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX -WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX -VIEWPORTSIZE VIEWPORTDIMENSION -VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS -FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR - -CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID - -]] - --- keywords - shouldn't be left out -for w in keyw:gmatch("([_%w]+)") do - api[w] = {type="keyword"} -end - -return api - - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/glsl/std.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/glsl/std.lua deleted file mode 100644 index 300af6d..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/glsl/std.lua +++ /dev/null @@ -1,277 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - --- function helpers - -local function fn (description) - local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())") - if not description2 then - return {type="function",description=description, - returns="(?)"} - end - return {type="function",description=description2, - returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args} -end - -local function val (description) - return {type="value",description = description} -end --- docs -local api = { -radians = fn "converts degrees to radians - (vecN)(vecN)", -degrees = fn "converts radians to degrees - (vecN)(vecN)", -sin = fn "returns sine of scalars and vectors. - (vecN)(vecN)", -sinh = fn "returns hyperbolic sine of scalars and vectors. - (vecN)(vecN)", -cos = fn "returns cosine of scalars and vectors. - (vecN)(vecN)", -cosh = fn "returns hyperbolic cosine of scalars and vectors. - (vecN)(vecN)", -atan = fn "returns arc tangent of scalars and vectors. - (vecN)([vecN y_over_x ]/[vecN y, vecN x])", -asin = fn "returns arc sine of scalars and vectors. - (vecN)(vecN)", -acos = fn "returns arc cosine of scalars and vectors. - (vecN)(vecN)", -atan = fn "returns arc tangent of scalars and vectors. - (vecN)(vecN)", -tan = fn "returns tangent of scalars and vectors. - (vecN)(vecN)", -tanh = fn "returns hyperbolic tangent of scalars and vectors. - (vecN)(vecN)", -acosh = fn "returns hyperbolic arc cosine of scalars and vectors. - (vecN)(vecN)", -asinh = fn "returns hyperbolic arc sine of scalars and vectors. - (vecN)(vecN)", -atanh = fn "returns hyperbolic arc tangent of scalars and vectors. - (vecN)(vecN)", - -exp = fn "returns the base-e exponential of scalars and vectors. - (vecN)(vecN)", -exp2 = fn "returns the base-2 exponential of scalars and vectors. - (vecN)(vecN)", -log = fn "returns the natural logarithm of scalars and vectors. - (vecN)(vecN)", -log2 = fn "returns the base-2 logarithm of scalars and vectors. - (vecN)(vecN)", -pow = fn "returns x to the y-th power of scalars and vectors. - (vecN)(vecN x, y)", -sqrt = fn "returns square root of scalars and vectors. - (vecN)(vecN)", -inversesqrt = fn "returns inverse square root of scalars and vectors. - (vecN)(vecN)", - -abs = fn "returns absolute value of scalars and vectors. - (vecN)(vecN)", -sign = fn "returns sign (1 or -1) of scalar or each vector component. - (vecN)(vecN)", -floor = fn "returns largest integer not greater than a scalar or each vector component. - (vecN)(vecN)", -ceil = fn "returns smallest integer not less than a scalar or each vector component. - (vecN)(vecN)", -trunc = fn "returns largest integer not greater than a scalar or each vector component. - (vecN)(vecN)", -round = fn "returns the rounded value of scalars or vectors. - (vecN)(vecN a)", -roundEven = fn "returns the nearest even integer value of scalars or vectors. - (vecN)(vecN a)", -fract = fn "returns the fractional portion of a scalar or each vector component. - (vecN)(vecN)", -mod = fn "modulus - (vecN)(vecN x, y)", -modf = fn "separate integer and fractional parts. - (vecN)(vecN x, out vecN i)", -max = fn "returns the maximum of two scalars or each respective component of two vectors. - (vecN)(vecN a, b)", -min = fn "returns the minimum of two scalars or each respective component of two vectors. - (vecN)(vecN a, b)", -mix = fn "returns linear interpolation of two scalars or vectors based on a weight. - (vecN)(vecN a, b, weight)", -step = fn "implement a step function returning either zero or one (x >= edge). - (vecN)(vecN edge, x)", - -isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(vecN)", -isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(vecN)", -clamp = fn "returns x clamped to the range [a,b]. - (vecN)(vecN x, a, b)", -smoothstep = fn "clip and smooth blend [a,b]. - (vecN)(vecN a, b, x)", -floatBitsToInt = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (uintN/intN)(floatN)", -intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)", -uintBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(uintN)", -doubleBitsToInt64 = fn "returns the 64-bit integer representation of an IEEE 754 double precision floating-point scalar or vector - (int64N)(doubleN)", -doubleBitsToUint64 = fn "returns the 64-bit integer representation of an IEEE 754 double precision floating-point scalar or vector - (uint64N)(doubleN)", -int64BitsToDouble = fn "returns the double value corresponding to a given bit represention.of a scalar int value or vector of int values. - (doubleN)(uint64N)", -uint64BitsToDouble = fn "returns the double value corresponding to a given bit represention.of a scalar int value or vector of int values. - (doubleN)(uint64N)", - -fma = fn "return a*b + c, treated as single operation when using precise - (vecN a, vecN b, vecN c)", -frexp = fn "splits scalars and vectors into normalized fraction [0.5,1.0) and a power of 2. - (vecN)(vecN x, out vecN e)", -ldexp = fn "build floating point number from x and the corresponding integral exponen of 2 in exp. - (vecN)(vecN x, exp)", - -packUnorm2x16 = fn "Converts each comp. of v into 16-bit ints, packs results into the returned 32-bit uint. - (uint)(vec2 v)", -packUnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)", -packSnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)", -packDouble2x32 = fn "Packs components of v into a 64-bit value and returns a double-prec value. - (double)(uvec2 v)", -packHalf2x16 = fn "Converts each comp. of v into 16-bit half float, packs results into the returned 32-bit uint. - (uint)(vec2 v)", -packInt2x32 = fn "Packs two 32 bit into one 64-bit value. - (int64_t)(ivec2)", -packUint2x32 = fn "Packs two 32 bit into one 64-bit value. - (uint64_t)(uvec2)", -packFloat2x16 = fn "returns an unsigned integer obtained by interpreting the components of a two-component 16-bit floating-point as integers and packing them into 32 bit. - (uint)(f16vec2 v)", - -unpackUnorm2x16 = fn "Unpacks 32-bit p into two 16-bit uints and converts them to normalized float. - (vec2)(uint p)", -unpackUnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)", -unpackSnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)", -unpackDouble2x32 = fn "Returns a 2 component vector representation of v. - (uvec2)(double v)", -unpackHalf2x16 = fn "Interprets p as two 16-bit half floats and returns them as vector. - (vec2)(uint p)", -unpackInt2x32 = fn "Unpacks 64-bit into two 32-bit values. - (ivec2)(int64_t)", -unpackUint2x32 = fn "Unpacks 64-bit into two 32-bit values. - (uvec2)(uint64_t)", -unpackFloat2x16 = fn "returns a two-component vector with 16-bit floating-point components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values. - (f16vec2)(uint)", - - -length = fn "return scalar Euclidean length of a vector. - (type)(vecN)", -distance = fn "return the Euclidean distance between two points. - (vecN)(vecN a, b)", -dot = fn "returns the scalar dot product of two vectors. - (type)(vecN a, b)", -cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)", -normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (vecN)(vecN)", -reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (vecN)(vecN incidence, normal)", -refract = fn "computes a refraction vector. - (vecN)(vecN incidence, normal, type eta)", -faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (vecN)(vecN Nperturbated, Incident, Ngeometric)", - -determinant = fn "returns the scalar determinant of a square matrix. - (float)(matN)", -transpose = fn "returns transpose matrix of a matrix. - (matNxM)(matMxN)", -inverse = fn "returns inverse matrix of a matrix. - (matN)(mat)", -matrixCompMult = fn "component-wise multiply. - (mat)(mat a, b)", -outerProduct = fn "outer product. - (matNxM)(vecM c, vecN r)", - -all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)", -any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)", -["not"] = fn "returns logical complement. - (boolN)(boolN)", -lessThan = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", -lessThanEqual = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", -greaterThan = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", -greaterThanEqual = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", -equal = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", -notEqual = fn "returns retusult of component-wise comparison. - (boolN)(vecN a,b)", - -uaddCarry = fn "Adds 32-bit uintx and y, returning the sum modulo 2^32. - (uintN)(uintN x, y, out carry)", -usubBorrow = fn "Subtracts y from x, returning the difference if non-negative otherwise 2^32 plus the difference. - (uint)(uint x, y, out borrow)", -umulExtended = fn "Multiplies 32-bit integers x and y producing 64-bit result. (uintN)(uintN x, y, out msb, out lsb)", -imulExtended = fn "Multiplies 32-bit integers x and y producing 64-bit result. (intN)(intN x, y, out msb, out lsb)", -bitfieldExtract = fn "Extracts bits (offset, offset + bits -1) from value and returns them in lsb of result. - (intN)(intN value, int offset, int bits)", -bitfieldInsert = fn "Returns the insertion the bits lsb of insert into base. - (intN)(intN base insert, int offset, int bits)", -bitfieldReverse = fn "Returns the reversal of the bits. - (intN)(intN)", -bitCount = fn "returns the number of bits set to 1. - (intN)(intN)", -findLSB = fn "returns bit number of lsb. - (intN)(intN)", -findMSB = fn "returns bit number of msb. - (intN)(intN)", - -discard = fn "conditionally (<0) kill a pixel before output. - ()(vecN)", -dFdx = fn "returns approximate partial derivative with respect to window-space X. - (vecN)(vecN)", -dFdxCoarse = fn "returns approximate partial derivative with respect to window-space X. - (vecN)(vecN)", -dFdxFine = fn "returns approximate partial derivative with respect to window-space X. - (vecN)(vecN)", -dFdy = fn "returns approximate partial derivative with respect to window-space Y. - (vecN)(vecN)", -dFdyCoarse = fn "returns approximate partial derivative with respect to window-space Y. - (vecN)(vecN)", -dFdyFine = fn "returns approximate partial derivative with respect to window-space Y. - (vecN)(vecN)", -fwidth = fn "returns abs sum of approximate window-space partial derivatives magnitudes. - (vecN)(vecN)", -fwidthFine = fn "returns abs sum of approximate window-space partial derivatives magnitudes. - (vecN)(vecN)", -fwidthCoarse = fn "returns abs sum of approximate window-space partial derivatives magnitudes. - (vecN)(vecN)", -interpolateAtCentroid = fn "Return value of interpolant sampled inside pixel and the primitive. - (floatN)(floatN)", -interpolateAtSample = fn "Return value of interpolant at the location fo sample. - (floatN)(floatN, int sample)", -interpolateAtOffset = fn "Return value of interpolant sampled at fixed offset offset from pixel center. - (floatN)(floatN, vec2 offset)", - -noise1 = fn "returns noise value. - (float)(float)", -noise2 = fn "returns noise value. - (vec2)(float)", -noise3 = fn "returns noise value. - (vec3)(float)", -noise4 = fn "returns noise value. - (vec4)(float)", - -EmitStreamVertex = fn "Emits values of the output variables of the current output primitive stream. - ()(int stream)", -EndStreamPrimitive = fn "Completes current output primitive stream and starts a new one. - ()(int stream)", -EmitVertex= fn "Emits values of the output variable of the current output primitive. - ()()", -EndPrimitive = fn "Completes current output primitive and starts a new one. - ()()", -barrier = fn "Synchronizes across shader invocations. - ()()", - -memoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()", -memoryBarrierAtomicCounter = fn "control ordering of memory transactions issued by shader thread. - ()()", -memoryBarrierShared = fn "control ordering of memory transactions issued by shader thread. - ()()", -memoryBarrierBuffer = fn "control ordering of memory transactions issued by shader thread. - ()()", -memoryBarrierImage = fn "control ordering of memory transactions issued by shader thread. - ()()", -groupMemoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()", -imageAtomicAdd = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicMin = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicMax = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicIncWrap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicDecWrap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicAnd = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicOr = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicXor = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicExchange = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageAtomicCompSwap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)", -imageStore = fn "stores the texel at the coordinate. - ()(imageN, intN coord, [int sample], vecN data)", -imageLoad = fn "loads the texel at the coordinate. - (vecN)(imageN, intN coord, [int sample])", -imageSize = fn "returns the size of the image. - (ivecN)(imageN)", -imageSamples = fn "returns the samples of the multi-sampled image. - (int)(image2DMSN)", - -atomicCounterIncrement = fn "increments counter and returns old value. - (uint)(atomic_uint)", -atomicCounterDecrement = fn "decrements counter and returns old value. - (uint)(atomic_uint)", -atomicCounter = fn "returns current counter value. - (uint)(atomic_uint)", -atomicMin = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicMax = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicAdd = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicAnd = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicOr = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicXor = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicExchange = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", -atomicCompSwap = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)", - -textureSize = fn "returns the size of the texture (no lod required: Rect, MS and Buffer). - (intN)(samplerN, [int lod])", -textureSamples = fn "returns the samples of the multi-sampled texture. - (int)(texture2DMSN)", -textureQueryLod = fn "returns the lod values for a given coordinate. - (vec2)(samplerN, vecN coord)", -texture = fn "performs a texture lookup. Shadow samplers require base N+1 coordinate. Lod bias is optional (illegal for MS, Buffer, Rect). - (vec4)(samplerN, vecN coord, [float bias])", -textureProj = fn "performas a projective texture lookup (only Nd samplers + Rect). Shadows require N+1 base coordinate, no Lod bias allowed for Rect. - (vec4)(samplerN, vecN+1 coord, [float bias])", -textureLod = fn "performs a lookup with explicit LOD. Shadows require N+1 base coordinate. Illegal function for Rect, MS, Buffer. - (vec4)(samplerN, vecN coord, float lod)", -textureOffset = fn "offset added before texture lookup. Illegal for MS, Buffer, Cube. - (vec4)(samplerN, vecN coord, intN offset, [float bias])", -textureProjOffset = fn "projective texture lookup with offset. Illegal for MS, Buffer, Cube, Array. - (vec4)(samplerN, vecN+1 coord, intN offset, [float bias])", -textureLodOffset = fn "offset added with explicit LOD. - (vec4)(samplerN, vecN coord, intN offset, int lod)", -textureProjLodOffset = fn "projective lookup with offset and explicit LOD. - (vec4)(samplerN, vecN+1 coord, intN offset, int lod)", -textureGrad = fn "lookup with explicit gradients. Illegal for MS, Buffer. - (vec4)(samplerN, vecN coord, gradX, gradY)", -textureGradOffset = fn "lookup with explicit gradients and offset. Illegal for MS, Buffer, Cube. - (vec4)(samplerN, vecN coord, gradX, gradY, intN offset)", -textureProjGradOffset = fn "projective lookup with expicit gradients and offset. Illegal for MS, Buffer, Cube. - (vec4)(samplerN, vecN+1 coord, vecN gradX, gradY, intN offset)", -textureGather = fn "gather lookup (pixel quad of 4 single channel samples at once). Component 0: x, 1: y ... is ignored for shadow samplers instead reference value must be passed. Only 2D/Cube. Illegal for MS. - (vec4)(samplerN, vecN coord, [int comp] / float shadowRefZ)", -textureGatherOffset = fn "gather lookup (pixel quad of 4 single channel samples at once) with offset. Component 0: x, 1: y ... is ignored for shadow samplers instead reference value must be passed. Only 2D/Cube. Illegal for MS. - (vec4)(samplerN, vecN coord, [float shadowRefZ], intN offset / intN offset[4] , [int comp])", -texelFetch = fn "integer coordinate lookup for a single texel. No lod parameter for Buffer, MS, Rect. Illegal for Cube - (vec4)(samplerN, intN coord, [int lod/sample])", -texelFetchOffset = fn "integer coordinate lookup for a single texel with offset. No lod parameter for Buffer, MS, Rect. Illegal for Cube, Buffer, MS. - (vec4)(samplerN, intN coord, [int lod/sample], intN offset)", - -anyInvocationARB = fn "returns true if and only if is true for at least one active invocation in the group. - (bool)(bool value)", -allInvocationsARB = fn "returns true if and only if is true for all active invocations in the group - (bool)(bool value)", -allInvocationsEqualARB = fn "returns true if is the same for all active invocation in the group. - (bool)(bool value)", -} - -local keyw = -[[ int uint half float bool double atomic_uint binding offset - vec2 vec3 vec4 dvec2 dvec3 dvec4 - ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4 - mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4 - dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4 - float16_t f16vec2 f16vec3 f16vec4 - float32_t f32vec2 f32vec3 f32vec4 - float64_t f64vec2 f64vec3 f64vec4 - int8_t i8vec2 i8vec3 i8vec4 - int8_t i8vec2 i8vec3 i8vec4 - int16_t i16vec2 i16vec3 i16vec4 - int32_t i32vec2 i32vec3 i32vec4 - int64_t i64vec2 i64vec3 i64vec4 - uint8_t u8vec2 u8vec3 u8vec4 - uint16_t u16vec2 u16vec3 u16vec4 - uint32_t u32vec2 u32vec3 u32vec4 - uint64_t u64vec2 u64vec3 u64vec4 - struct typedef void - usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray - isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray - sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray - sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow - usamplerBuffer isamplerBuffer samplerBuffer samplerRenderbuffer isamplerRenderbuffer usamplerRenderbuffer - in out inout uniform const centroid sample attribute varying patch index true false - return switch case for do while if else break continue main inline - layout location vertices line_strip triangle_strip max_vertices stream - triangles quads equal_spacing isolines fractional_even_spacing lines points - fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency - invocations offset align xfb_offset xfb_buffer - origin_upper_left pixel_center_integer depth_greater depth_greater depth_greater depth_unchanged - smooth flat noperspective highp mediump lowp shared packed std140 std430 row_major column_major buffer - gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor - subroutine gl_Position gl_FragCoord - gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 - gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 - gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance - gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in - gl_PatchVerticesIn - gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord - gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing - gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor - gl_FragData gl_FragDepth gl_SampleMask - gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex - local_size_x local_size_y local_size_z - gl_BaseVertexARB gl_BaseInstanceARB gl_DrawIDARB - bindless_sampler bound_sampler bindless_image bound_image early_fragment_tests - gl_HelperInvocation gl_CullDistance gl_MaxSamples - - coherent volatile restrict readonly writeonly - image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray - uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray - iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray - size1x8 size1x16 size1x32 size2x32 size4x32 rgba32f rgba16f rg32f rg16f r32f r16f rgba8 rgba16 r11f_g11f_b10f rgb10_a2ui - rgb10_a2i rg16 rg8 r16 r8 rgba32i rgba16i rgba8i rg32i rg16i rg8i r32i r16i r8i rgba32ui rgba16ui rgba8ui rg32ui rg16ui rg8ui - r32ui r16ui r8ui rgba16_snorm rgba8_snorm rg16_snorm rg8_snorm r16_snorm r8_snorm -]] - --- keywords - shouldn't be left out -for w in keyw:gmatch("([a-zA-Z_0-9]+)") do - api[w] = {type="keyword"} -end - -return api - - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/baselib.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/baselib.lua deleted file mode 100644 index 45a2fba..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/baselib.lua +++ /dev/null @@ -1,1238 +0,0 @@ -return { - -- covers Lua 5.1, Lua 5.2, and Lua 5.3; - -- Lua 5.2 and Lua 5.3 specific items are marked with - -- FUNCTION/ARGUMENT/ARGS/VALUE ADDED/DEPRECATED IN Lua 5.2 or Lua 5.3. - - -- Keywords - ["and"] = {type = "keyword"}, - ["break"] = {type = "keyword"}, - ["do"] = {type = "keyword"}, - ["else"] = {type = "keyword"}, - ["elseif"] = {type = "keyword"}, - ["end"] = {type = "keyword"}, - ["for"] = {type = "keyword"}, - ["function"] = {type = "keyword"}, - ["goto"] = {type = "keyword"}, - ["if"] = {type = "keyword"}, - ["in"] = {type = "keyword"}, - ["local"] = {type = "keyword"}, - ["not"] = {type = "keyword"}, - ["or"] = {type = "keyword"}, - ["repeat"] = {type = "keyword"}, - ["return"] = {type = "keyword"}, - ["then"] = {type = "keyword"}, - ["until"] = {type = "keyword"}, - ["while"] = {type = "keyword"}, - - -- Boolean values - ["false"] = {type = "value"}, - ["nil"] = {type = "value"}, - ["true"] = {type = "value"}, - - -- Basic library - _ENV = { - type = "value", - description = "VALUE ADDED IN Lua 5.2.", - }, - _G = { - type = "value", - description = "A global variable (not a function) that holds the global environment.\nLua itself does not use this variable; changing its value does not affect any environment, nor vice-versa.", - }, - _VERSION = { - type = "value", - description = "A global variable (not a function) that holds a string containing the current interpreter version.", - }, - assert = { - type = "function", - description = "Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments.\nmessage is an error message; when absent, it defaults to \"assertion failed!\"", - args = "(v: any [, message: string])", - returns = "(...)", - }, - collectgarbage = { - type = "function", - description = "This function is a generic interface to the garbage collector.\nIt performs different functions according to its first argument, opt:\n* \"collect\": performs a full garbage-collection cycle. This is the default option.\n* \"stop\": stops automatic execution of the garbage collector. The collector will run only when explicitly invoked, until a call to restart it.\n* \"restart\": restarts automatic execution of the garbage collector.\n* \"count\": returns the total memory in use by Lua (in Kbytes) and a second value with the total memory in bytes modulo 1024 (SECOND RETURN ADDED IN Lua 5.2). The first value has a fractional part, so the following equality is always true:\nk, b = collectgarbage(\"count\")\nassert(k*1024 == math.floor(k)*1024 + b)\n(The second result is useful when Lua is compiled with a non floating-point type for numbers.)\n* \"step\": performs a garbage-collection step. The step \"size\" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of arg. Returns true if the step finished a collection cycle.\n* \"setpause\": sets arg as the new value for the pause of the collector. Returns the previous value for pause.\n* \"setstepmul\": sets arg as the new value for the step multiplier of the collector. Returns the previous value for step.\n* \"isrunning\": returns a boolean that tells whether the collector is running (i.e., not stopped). VALUE ADDED IN Lua 5.2.\n* \"generational\": changes the collector to generational mode. This is an experimental feature. VALUE ADDED IN Lua 5.2.\n* \"incremental\": changes the collector to incremental mode. This is the default mode. VALUE ADDED IN Lua 5.2.", - args = "([opt: string [, arg: number]])", - returns = "(...)", - }, - dofile = { - type = "function", - description = "Opens the named file and executes its contents as a Lua chunk.\nWhen called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).", - args = "([filename: string])", - returns = "(...)", - }, - error = { - type = "function", - description = "Terminates the last protected function called and returns message as the error message.\nFunction error never returns.\nUsually, error adds some information about the error position at the beginning of the message, if the message is a string. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.", - args = "(message: string [, level: number])", - returns = "()", - }, - getfenv = { - type = "function", - description = "Returns the current environment in use by the function.\n\nf can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.\n\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "([f: function|number])", - returns = "(table)", - }, - getmetatable = { - type = "function", - description = "If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a \"__metatable\" field, returns the associated value. Otherwise, returns the metatable of the given object.", - args = "(object: any)", - returns = "(table|nil)", - valuetype = "m", - }, - ipairs = { - type = "function", - description = "If t has a metamethod __ipairs, calls it with t as argument and returns the first three results from the call. METAMETHOD BEHAVIOR ADDED IN Lua 5.2.\nOtherwise, returns three values: an iterator function, the table t, and 0, so that the construction\nfor i,v in ipairs(t) do body end\nwill iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key absent from the table.", - args = "(t: table)", - returns = "(function, table, number)", - }, - load = { - type = "function", - description = "Loads a chunk.\nIf ld is a string, the chunk is this string. If ld is a function, load calls it repeatedly to get the chunk pieces. Each call to ld must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.\nIf there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.\nIf the resulting function has upvalues, the first upvalue is set to the value of the global environment or to env, if that parameter is given. When loading main chunks, the first upvalue will be the _ENV variable. ARGUMENT ADDED IN Lua 5.2.\nsource is used as the source of the chunk for error messages and debug information. When absent, it defaults to ld, if ld is a string, or to \"=(load)\" otherwise.\nThe string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string \"b\" (only binary chunks), \"t\" (only text chunks), or \"bt\" (both binary and text). The default is \"bt\". ARGUMENT ADDED IN Lua 5.2.", - args = "(ld: string|function [, source: string [, mode: string [, env: table]]])", - returns = "(function|nil [, string])", - }, - loadfile = { - type = "function", - description = "Loads a chunk from file filename or from the standard input, if no file name is given.\nIf there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.\nIf the resulting function has upvalues, the first upvalue is set to the value of the global environment or to env, if that parameter is given. ARGUMENT ADDED IN Lua 5.2. When loading main chunks, the first upvalue will be the _ENV variable.\nThe string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string \"b\" (only binary chunks), \"t\" (only text chunks), or \"bt\" (both binary and text). The default is \"bt\". ARGUMENT ADDED IN Lua 5.2.", - args = "([filename: string [, mode: string [, env: table]]])", - returns = "(function|nil [, string])", - }, - loadstring = { - type = "function", - description = "Loads a chunk from the given string.\nIf there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.\nTo load and run a given string, use the idiom\nassert(loadstring(s))()\nWhen absent, chunkname defaults to the given string.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(string: string [, chunkname: string])", - returns = "(function|nil [, string])", - }, - next = { - type = "function", - description = "Allows a program to traverse all fields of a table.\nIts first argument is a table and its second argument is an index in this table. next returns the next index of the table and its associated value. When called with nil as its second argument, next returns an initial index and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.\nThe order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for.)\nThe behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.", - args = "(table: table [, index: any])", - returns = "(any [, any])", - }, - pairs = { - type = "function", - description = "If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call. METAMETHOD BEHAVIOR ADDED IN Lua 5.2.\nOtherwise, returns three values: the next function, the table t, and nil, so that the construction\nfor k,v in pairs(t) do body end\nwill iterate over all key–value pairs of table t.\nSee function next for the caveats of modifying the table during its traversal.", - args = "(t: table)", - returns = "(function, table, nil)", - }, - pcall = { - type = "function", - description = "Calls function f with the given arguments in protected mode.\nThis means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.", - args = "(f: function [, arg1: any, ...])", - returns = "(boolean, ...)", - }, - print = { - type = "function", - description = "Receives any number of arguments and prints their values to stdout, using the tostring function to convert each argument to a string.\nprint is not intended for formatted output, but only as a quick way to show a value, for instance for debugging. For complete control over the output, use string.format and io.write.", - args = "(...)", - returns = "()", - }, - rawequal = { - type = "function", - description = "Checks whether v1 is equal to v2, without invoking any metamethod.\nReturns a boolean.", - args = "(v1: any, v2: any)", - returns = "(boolean)", - }, - rawget = { - type = "function", - description = "Gets the real value of table[index], without invoking any metamethod.\ntable must be a table; index may be any value.", - args = "(table: table, index: any)", - returns = "(any)", - }, - rawlen = { - type = "function", - description = "Returns the length of the object v, which must be a table or a string, without invoking any metamethod.\nReturns an integer number.\nFUNCTION ADDED IN Lua 5.2.", - args = "(v: table|string)", - returns = "(number)", - }, - rawset = { - type = "function", - description = "Sets the real value of table[index] to value, without invoking any metamethod.\ntable must be a table, index any value different from nil and NaN, and value any Lua value.\nThis function returns table.", - args = "(table: table, index: any, value: any)", - returns = "(table)", - }, - select = { - type = "function", - description = "If index is a number, returns all arguments after argument number index.\nA negative number indexes from the end (-1 is the last argument). NEGATIVE VALUE ADDED IN Lua 5.2.\nOtherwise, index must be the string \"#\", and select returns the total number of extra arguments it received.", - args = "(index: number|string, ...)", - returns = "(...)", - }, - setfenv = { - type = "function", - description = "Sets the environment to be used by the given function.\nf can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling setfenv. setfenv returns the given function.\nAs a special case, when f is 0 setfenv changes the environment of the running thread. In this case, setfenv returns no values.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(f: function|number, table: table)", - returns = "([function])", - }, - setmetatable = { - type = "function", - description = "Sets the metatable for the given table.\n(You cannot change the metatable of other types from Lua, only from C.)\nIf metatable is nil, removes the metatable of the given table. If the original metatable has a \"__metatable\" field, raises an error.\nThis function returns table.", - args = "(table: table, metatable: table|nil)", - returns = "(table)", - valuetype = "m", - }, - tonumber = { - type = "function", - description = "When called with no base, tonumber tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns this number; otherwise, it returns nil.\nWhen called with base, then e should be a string to be interpreted as an integer numeral in that base. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. If the string e is not a valid numeral in the given base, the function returns nil.", - args = "(e: any [, base: number])", - returns = "(number|nil)", - }, - tostring = { - type = "function", - description = "Receives a value of any type and converts it to a string in a reasonable format.\n(For complete control of how numbers are converted, use string.format.)\nIf the metatable of v has a \"__tostring\" field, then tostring calls the corresponding value with v as argument, and uses the result of the call as its result.", - args = "(v: any)", - returns = "(string)", - valuetype = "string", - }, - type = { - type = "function", - description = "Returns the type of its only argument, coded as a string.\nThe possible results of this function are \"nil\" (a string, not the value nil), \"number\", \"string\", \"boolean\", \"table\", \"function\", \"thread\", and \"userdata\".", - args = "(v: any)", - returns = "(string)", - }, - unpack = { - type = "function", - description = "Returns the elements from the given table.\nThis function is equivalent to\nreturn list[i], list[i+1], ···, list[j]\nexcept that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, as defined by the length operator.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(list: table [, i: number [, j: number]])", - returns = "(...)", - }, - xpcall = { - type = "function", - description = "Calls function f with the given arguments in protected mode, using msgh as a message handler.\nThis means that any error inside f is not propagated; instead, xpcall catches the error, calls the msgh function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from msgh.\nADDITIONAL ARGS ADDED IN Lua 5.2.", - args = "(f: function, msgh: function [, arg1: any, ...])", - returns = "(boolean, ...)", - }, - - -- Coroutine library - coroutine = { - type = "lib", - description = "The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine.\nLua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.", - childs = { - create = { - type = "function", - description = "Creates a new coroutine, with body f.\nf must be a Lua function. Returns this new coroutine, an object with type \"thread\".", - args = "(f: function)", - returns = "(thread)", - }, - resume = { - type = "function", - description = "Starts or continues the execution of coroutine co.\nThe first time you resume a coroutine, it starts running its body. The values val1, ... are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ... are passed as the results from the yield.\nIf the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.", - args = "(co: thread [, val1: any, ...])", - returns = "(boolean, ...)", - }, - running = { - type = "function", - description = "Returns the running coroutine plus a boolean, true when the running coroutine is the main one.\nBOOLEAN RETURN ADDED IN Lua 5.2.", - args = "()", - returns = "(thread, boolean)", - }, - status = { - type = "function", - description = "Returns the status of coroutine co, as a string.\nThe status can be one of the following: \"running\", if the coroutine is running (that is, it called status); \"suspended\", if the coroutine is suspended in a call to yield, or if it has not started running yet; \"normal\" if the coroutine is active but not running (that is, it has resumed another coroutine); and \"dead\" if the coroutine has finished its body function, or if it has stopped with an error.", - args = "(co: thread)", - returns = "(string)", - }, - wrap = { - type = "function", - description = "Creates a new coroutine, with body f.\nf must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.", - args = "(f: function)", - returns = "(function)", - }, - yield = { - type = "function", - description = "Suspends the execution of the calling coroutine.\nAny arguments to yield are passed as extra results to resume.", - args = "(...)", - returns = "()", - }, - isyieldable = { - type = "function", - description = "Returns true when the running coroutine can yield. A running coroutine is yieldable if it is not the main thread and it is not inside a non-yieldable C function.\nFUNCTION ADDED IN Lua 5.3.", - args = "()", - returns = "(boolean)", - }, - }, - }, - - -- Module/Package library - module = { - type = "function", - description = "Creates a module.\nIf there is a table in package.loaded[name], this table is the module. Otherwise, if there is a global table t with the given name, this table is the module. Otherwise creates a new table t and sets it as the value of the global name and the value of package.loaded[name]. This function also initializes t._NAME with the given name, t._M with the module (t itself), and t._PACKAGE with the package name (the full module name minus last component; see below). Finally, module sets t as the new environment of the current function and the new value of package.loaded[name], so that require returns t.\nIf name is a compound name (that is, one with components separated by dots), module creates (or reuses, if they already exist) tables for each component.\nThis function can receive optional options after the module name, where each option is a function to be applied over the module.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(name: string [, ...])", - returns = "()", - }, - require = { - type = "function", - description = "Loads the given module.\nThe function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.\nTo find a loader, require is guided by the package.searchers sequence. By changing this sequence, we can change how require looks for a module. The following explanation is based on the default configuration for package.searchers.\nFirst require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see package.searchers).\nOnce a loader is found, require calls the loader with two arguments: modname and an extra value dependent on how it got the loader. (If the loader came from a file, this extra value is the file name.) If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].\nIf there is any error loading or running the module, or if it cannot find any loader for the module, then require raises an error.", - args = "(modname: string)", - returns = "(any)", - }, - package = { - type = "lib", - description = "The package library provides basic facilities for loading modules in Lua.\nIt exports one function directly in the global environment: require. Everything else is exported in a table package.", - childs = { - config = { - type = "value", - description = "A string describing some compile-time configurations for packages.\nThis string is a sequence of lines:\n* The first line is the directory separator string. Default is '\\' for Windows and '/' for all other systems.\n* The second line is the character that separates templates in a path. Default is ';'.\n* The third line is the string that marks the substitution points in a template. Default is '?'.\n* The fourth line is a string that, in a path in Windows, is replaced by the executable's directory. Default is '!'.\n* The fifth line is a mark to ignore all text before it when building the luaopen_ function name. Default is '-'.", - }, - cpath = { - type = "value", - description = "The path used by require to search for a C loader.\nLua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH_5_2 or the environment variable LUA_CPATH or a default path defined in luaconf.h.", - }, - loaded = { - type = "value", - description = "A table used by require to control which modules are already loaded.\nWhen you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.\nThis variable is only a reference to the real table; assignments to this variable do not change the table used by require.", - }, - loaders = { - type = "value", - description = "A table used by require to control how to load modules.\nEach entry in this table is a searcher function. When looking for a module, require calls each of these searchers in ascending order, with the module name (the argument given to require) as its sole parameter. The function can return another function (the module loader) or a string explaining why it did not find that module (or nil if it has nothing to say). Lua initializes this table with four functions.\nThe first searcher simply looks for a loader in the package.preload table.\nThe second searcher looks for a loader as a Lua library, using the path stored at package.path. A path is a sequence of templates separated by semicolons. For each template, the searcher will change each interrogation mark in the template by filename, which is the module name with each dot replaced by a \"directory separator\" (such as \"/\" in Unix); then it will try to open the resulting file name.\nThe third searcher looks for a loader as a C library, using the path given by the variable package.cpath. Once it finds a C library, this searcher first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside the library to be used as the loader. The name of this C function is the string \"luaopen_\" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed.\nThe fourth searcher tries an all-in-one loader. It searches the C path for a library for the root name of the given module. If found, it looks into it for an open function for the submodule. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.\nVALUE DEPRECATED IN Lua 5.2.", - }, - loadlib = { - type = "function", - description = "Dynamically links the host program with the C library libname.\nIf funcname is \"*\", then it only links with the library, making the symbols exported by the library available to other dynamically linked libraries. VALUE ADDED IN Lua 5.2.\nOtherwise, it looks for a function funcname inside the library and returns this function as a C function. (So, funcname must follow the prototype lua_CFunction).\nThis is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and an extension. funcname must be the exact name exported by the C library (which may depend on the C compiler and linker used).\nThis function is not supported by Standard C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard).", - args = "(libname: string, funcname: string)", - returns = "([function])", - }, - path = { - type = "value", - description = "The path used by require to search for a Lua loader.\nAt start-up, Lua initializes this variable with the value of the environment variable LUA_PATH_5_2 or the environment variable LUA_PATH or with a default path defined in luaconf.h, if those environment variables are not defined. Any \";;\" in the value of the environment variable is replaced by the default path.", - }, - preload = { - type = "value", - description = "A table to store loaders for specific modules (see require).\nThis variable is only a reference to the real table; assignments to this variable do not change the table used by require.", - }, - searchers = { - type = "value", - description = "A table used by require to control how to load modules.\nEach entry in this table is a searcher function. When looking for a module, require calls each of these searchers in ascending order, with the module name (the argument given to require) as its sole parameter. The function can return another function (the module loader) plus an extra value that will be passed to that loader, or a string explaining why it did not find that module (or nil if it has nothing to say).\nLua initializes this table with four searcher functions.\nThe first searcher simply looks for a loader in the package.preload table.\nThe second searcher looks for a loader as a Lua library, using the path stored at package.path. The search is done as described in function package.searchpath.\nThe third searcher looks for a loader as a C library, using the path given by the variable package.cpath. Again, the search is done as described in function package.searchpath. Once it finds a C library, this searcher first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside the library to be used as the loader. The name of this C function is the string \"luaopen_\" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed.\nThe fourth searcher tries an all-in-one loader. It searches the C path for a library for the root name of the given module. If found, it looks into it for an open function for the submodule. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.\nAll searchers except the first one (preload) return as the extra value the file name where the module was found, as returned by package.searchpath. The first searcher returns no extra value.\nVALUE ADDED IN Lua 5.2.", - }, - searchpath = { - type = "function", - description = "Searches for the given name in the given path.\nA path is a string containing a sequence of templates separated by semicolons. For each template, the function replaces each interrogation mark (if any) in the template with a copy of name wherein all occurrences of sep (a dot, by default) were replaced by rep (the system's directory separator, by default), and then tries to open the resulting file name.\nReturns the resulting name of the first file that it can open in read mode (after closing the file), or nil plus an error message if none succeeds. (This error message lists all file names it tried to open.)\nFUNCTION ADDED IN Lua 5.2.", - args = "(name: string, path: string [, sep: string [, rep: string]])", - returns = "(string|nil [, string])", - }, - seeall = { - type = "function", - description = "Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment.\nTo be used as an option to function module.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(module: table)", - returns = "()", - }, - }, - }, - - -- String library - string = { - type = "lib", - description = "This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching.\nWhen indexing a string in Lua, the first character is at position 1 (not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.\nThe string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s,i) can be written as s:byte(i).\nThe string library assumes one-byte character encodings.", - childs = { - byte = { - type = "function", - description = "Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j].\nThe default value for i is 1; the default value for j is i. These indices are corrected following the same rules of function string.sub.\nNumerical codes are not necessarily portable across platforms.", - args = "(s: string [, i: number [, j: number]])", - returns = "(number [, ...])", - }, - char = { - type = "function", - description = "Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument.\nNumerical codes are not necessarily portable across platforms.", - args = "(...)", - returns = "(string)", - valuetype = "string", - }, - dump = { - type = "function", - description = "Returns a string containing a binary representation of the given function, so that a later load on this string returns a copy of the function (but with new upvalues).", - args = "(function: function)", - returns = "(string)", - valuetype = "string", - }, - find = { - type = "function", - description = "Looks for the first match of pattern in the string s.\nIf it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil.\nA third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain \"find substring\" operation, with no characters in pattern being considered magic. Note that if plain is given, then init must be given as well.\nIf the pattern has captures, then in a successful match the captured values are also returned, after the two indices.", - args = "(s: string, pattern: string [, init: number [, plain: boolean]])", - returns = "(number|nil [, number [, ...]])", - }, - format = { - type = "function", - description = "Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string).\nThe format string follows the same rules as the C function sprintf. The only differences are that the options/modifiers *, h, L, l, n, and p are not supported and that there is an extra option, q. The q option formats a string between double quotes, using escape sequences when necessary to ensure that it can safely be read back by the Lua interpreter.\nOptions A and a (when available) (VALUES ADDED IN Lua 5.2), E, e, f, G, and g all expect a number as argument. Options c, d, i, o, u, X, and x also expect a number, but the range of that number may be limited by the underlying C implementation. For options o, u, X, and x, the number cannot be negative. Option q expects a string; option s expects a string without embedded zeros. If the argument to option s is not a string, it is converted to one following the same rules of tostring (BEHAVIOR ADDED IN Lua 5.2).", - args = "(formatstring, ...)", - returns = "(string)", - valuetype = "string", - }, - gmatch = { - type = "function", - description = "Returns an iterator function that, each time it is called, returns the next captures from pattern over the string s.\nIf pattern specifies no captures, then the whole match is produced in each call.\nFor this function, a caret '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration.", - args = "(s: string, pattern: string)", - returns = "(function)", - }, - pack = { - type = "function", - description = "Returns a binary string containing the values v1, v2, etc. packed (that is, serialized in binary form) according to the format string fmt.\nFUNCTION ADDED IN Lua 5.3.", - args = "(fmt: string, v1, v2, ...)", - returns = "(string)", - valuetype = "string", - }, - unpack = { - type = "function", - description = "Returns the values packed in string s (see string.pack) according to the format string fmt. An optional pos marks where to start reading in s (default is 1). After the read values, this function also returns the index of the first unread byte in s.\nFUNCTION ADDED IN Lua 5.3.", - args = "(fmt: string, s: string [, pos: number])", - returns = "(values)", - }, - packsize = { - type = "function", - description = "Returns the size of a string resulting from string.pack with the given format. The format string cannot have the variable-length options 's' or 'z'.\nFUNCTION ADDED IN Lua 5.3.", - args = "(fmt: string)", - returns = "(number)", - }, - gsub = { - type = "function", - description = "Returns a copy of s in which all (or the first n, if given) occurrences of the pattern have been replaced by a replacement string specified by repl, which can be a string, a table, or a function.\ngsub also returns, as its second value, the total number of matches that occurred. The name gsub comes from Global SUBstitution.\nIf repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.\nIf repl is a table, then the table is queried for every match, using the first capture as the key.\nIf repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order.\nIn any case, if the pattern specifies no captures, then it behaves as if the whole pattern was inside a capture.\nIf the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).", - args = "(s: string, pattern: string, repl: string|table|function [, n: number])", - returns = "(string, number)", - valuetype = "string", - }, - len = { - type = "function", - description = "Receives a string and returns its length.\nThe empty string \"\" has length 0. Embedded zeros are counted, so \"a\\000bc\\000\" has length 5.", - args = "(s: string)", - returns = "(number)", - }, - lower = { - type = "function", - description = "Receives a string and returns a copy of this string with all uppercase letters changed to lowercase.\nAll other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale.", - args = "(s: string)", - returns = "(string)", - valuetype = "string", - }, - match = { - type = "function", - description = "Looks for the first match of pattern in the string s.\nIf it finds one, then match returns the captures from the pattern; otherwise it returns nil.\nIf pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative.", - args = "(s: string, pattern: string [, init: number])", - returns = "(string|nil [,...])", - valuetype = "string", - }, - rep = { - type = "function", - description = "Returns a string that is the concatenation of n copies of the string s separated by the string sep.\nThe default value for sep is the empty string (that is, no separator). ARGUMENT ADDED IN Lua 5.2.", - args = "(s: string, n: number [, sep: string])", - returns = "(string)", - valuetype = "string", - }, - reverse = { - type = "function", - description = "Returns a string that is the string s reversed.", - args = "(s: string)", - returns = "(string)", - valuetype = "string", - }, - sub = { - type = "function", - description = "Returns the substring of s that starts at i and continues until j; i and j can be negative.\nIf j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.\nIf, after the translation of negative indices, i is less than 1, it is corrected to 1. If j is greater than the string length, it is corrected to that length. If, after these corrections, i is greater than j, the function returns the empty string.", - args = "(s: string, i: number [, j: number])", - returns = "(string)", - valuetype = "string", - }, - upper = { - type = "function", - description = "Receives a string and returns a copy of this string with all lowercase letters changed to uppercase.\nAll other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale.", - args = "(s: string)", - returns = "(string)", - valuetype = "string", - }, - }, - }, - - -- Table library - table = { - type = "lib", - description = "This library provides generic functions for table manipulation. It provides all its functions inside the table table.\nRemember that, whenever an operation needs the length of a table, the table should be a proper sequence or have a __len metamethod. All functions ignore non-numeric keys in tables given as arguments.\nFor performance reasons, all table accesses (get/set) performed by these functions are raw.", - childs = { - concat = { - type = "function", - description = "Given a list where all elements are strings or numbers, returns list[i]..sep..list[i+1] ··· sep..list[j].\nThe default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.", - args = "(list: table [, sep: string [, i: number [, j: number]]])", - returns = "(string)", - valuetype = "string", - }, - insert = { - type = "function", - description = "Inserts element value at position pos in list, shifting up the elements list[pos], list[pos+1], ···, list[#list].\nThe default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t.", - args = "(list: table, [pos: number,] value: any)", - returns = "()", - }, - maxn = { - type = "function", - description = "Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices.\n(To do its job this function does a linear traversal of the whole table.)\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(table: table)", - returns = "(number)", - }, - pack = { - type = "function", - description = "Returns a new table with all parameters stored into keys 1, 2, etc. and with a field \"n\" with the total number of parameters.\nNote that the resulting table may not be a sequence.\nFUNCTION ADDED IN Lua 5.2.", - args = "(...)", - returns = "(table)", - }, - move = { - type = "function", - description = "Moves elements from table a1 to table a2. This function performs the equivalent to the following multiple assignment: a2[t],··· = a1[f],···,a1[e]. The default for a2 is a1. The destination range can overlap with the source range. Index f must be positive.\nFUNCTION ADDED IN Lua 5.3.", - args = "(a1: table, f, e, t [,a2: table])", - returns = "()", - }, - remove = { - type = "function", - description = "Removes from list the element at position pos, shifting down the elements list[pos+1], list[pos+2], ···, list[#list] and erasing element list[#list].\nReturns the value of the removed element.\nThe default value for pos is #list, so that a call table.remove(t) removes the last element of list t.", - args = "(list: table [, pos: number])", - returns = "(any)", - }, - sort = { - type = "function", - description = "Sorts list elements in a given order, in-place, from list[1] to list[#list].\nIf comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that not comp(list[i+1],list[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead.\nThe sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.", - args = "(list: table [, comp: function])", - returns = "()", - }, - unpack = { - type = "function", - description = "Returns the elements from the given table.\nThis function is equivalent to\nreturn list[i], list[i+1], ···, list[j]\nBy default, i is 1 and j is #list.\nFUNCTION ADDED IN Lua 5.2.", - args = "(list: table [, i: number [, j: number]])", - returns = "(...)", - }, - }, - }, - - -- Math library - math = { - type = "lib", - description = "This library is an interface to the standard C math library. It provides all its functions inside the table math.", - childs = { - abs = { - type = "function", - description = "Returns the absolute value of x.", - args = "(x: number)", - returns = "(number)", - }, - acos = { - type = "function", - description = "Returns the arc cosine of x (in radians).", - args = "(x: number)", - returns = "(number)", - }, - asin = { - type = "function", - description = "Returns the arc sine of x (in radians).", - args = "(x: number)", - returns = "(number)", - }, - atan = { - type = "function", - description = "Returns the arc tangent of x (in radians).", - args = "(x: number)", - returns = "(number)", - }, - atan2 = { - type = "function", - description = "Returns the arc tangent of y/x (in radians), but uses the signs of both parameters to find the quadrant of the result.\n(It also handles correctly the case of x being zero.)", - args = "(y: number, x: number)", - returns = "(number)", - }, - ceil = { - type = "function", - description = "Returns the smallest integer larger than or equal to x.", - args = "(x: number)", - returns = "(number)", - }, - cos = { - type = "function", - description = "Returns the cosine of x (assumed to be in radians).", - args = "(x: number)", - returns = "(number)", - }, - cosh = { - type = "function", - description = "Returns the hyperbolic cosine of x.", - args = "(x: number)", - returns = "(number)", - }, - deg = { - type = "function", - description = "Returns the angle x (given in radians) in degrees.", - args = "(x: number)", - returns = "(number)", - }, - exp = { - type = "function", - description = "Returns the value exp(x).", - args = "(x: number)", - returns = "(number)", - }, - floor = { - type = "function", - description = "Returns the largest integer smaller than or equal to x.", - args = "(x: number)", - returns = "(number)", - }, - fmod = { - type = "function", - description = "Returns the remainder of the division of x by y that rounds the quotient towards zero.", - args = "(x: number, y: number)", - returns = "(number)", - }, - frexp = { - type = "function", - description = "Returns m and e such that x = m2^e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).", - args = "(x: number)", - returns = "(number, number)", - }, - huge = { - type = "value", - description = "The value HUGE_VAL, a value larger than or equal to any other numerical value.", - }, - ldexp = { - type = "function", - description = "Returns m2^e (e should be an integer).", - args = "(m: number, e: number)", - returns = "(number)", - }, - log = { - type = "function", - description = "Returns the logarithm of x in the given base.\nThe default for base is e (so that the function returns the natural logarithm of x). ARGUMENT ADDED IN Lua 5.2.", - args = "(x: number [, base: number])", - returns = "(number)", - }, - log10 = { - type = "function", - description = "Returns the base-10 logarithm of x.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(x: number)", - returns = "(number)", - }, - max = { - type = "function", - description = "Returns the maximum value among its arguments.", - args = "(x: number, ...)", - returns = "(number)", - }, - min = { - type = "function", - description = "Returns the minimum value among its arguments.", - args = "(x: number, ...)", - returns = "(number)", - }, - modf = { - type = "function", - description = "Returns two numbers, the integral part of x and the fractional part of x.", - args = "(x: number)", - returns = "(number, number)", - }, - pi = { - type = "value", - description = "The value of pi.", - }, - mininteger = { - type = "value", - description = "An integer with the minimum value for an integer.\nVALUE ADDED IN Lua 5.3.", - }, - maxinteger = { - type = "value", - description = "An integer with the maximum value for an integer.\nVALUE ADDED IN Lua 5.3.", - }, - pow = { - type = "function", - description = "Returns x^y.\n(You can also use the expression x^y to compute this value.)", - args = "(x: number, y: number)", - returns = "(number)", - }, - rad = { - type = "function", - description = "Returns the angle x (given in degrees) in radians.", - args = "(x: number)", - returns = "(number)", - }, - random = { - type = "function", - description = "This function is an interface to the simple pseudo-random generator function rand provided by Standard C.\n(No guarantees can be given for its statistical properties.)\nWhen called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].", - args = "([m: number [, n: number]])", - returns = "(number)", - }, - randomseed = { - type = "function", - description = "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.", - args = "(x: number)", - returns = "()", - }, - sin = { - type = "function", - description = "Returns the sine of x (assumed to be in radians).", - args = "(x: number)", - returns = "(number)", - }, - sinh = { - type = "function", - description = "Returns the hyperbolic sine of x.", - args = "(x: number)", - returns = "(number)", - }, - sqrt = { - type = "function", - description = "Returns the square root of x.\n(You can also use the expression x^0.5 to compute this value.)", - args = "(x: number)", - returns = "(number)", - }, - tan = { - type = "function", - description = "Returns the tangent of x (assumed to be in radians).", - args = "(x: number)", - returns = "(number)", - }, - tanh = { - type = "function", - description = "Returns the hyperbolic tangent of x.", - args = "(x: number)", - returns = "(number)", - }, - type = { - type = "function", - description = [[Returns "integer" if x is an integer, "float" if it is a float, or nil if x is not a number.\nFUNCTION ADDED IN Lua 5.3.]], - args = "(x: number)", - returns = "(string)", - }, - tointeger = { - type = "function", - description = "If the value x is convertible to an integer, returns that integer. Otherwise, returns nil.\nFUNCTION ADDED IN Lua 5.3.", - args = "(x: number)", - returns = "(number)", - }, - ult = { - type = "function", - description = "Returns a boolean, true if integer m is below integer n when they are compared as unsigned integers.\nFUNCTION ADDED IN Lua 5.3.", - args = "(m: number, n: number)", - returns = "(boolean)", - }, - }, - }, - - -- Bitwise library - bit32 = { - type = "lib", - description = "This library provides bitwise operations. It provides all its functions inside the table bit32.\nUnless otherwise stated, all functions accept numeric arguments in the range (-2^51,+2^51); each argument is normalized to the remainder of its division by 2^32 and truncated to an integer (in some unspecified way), so that its final value falls in the range [0,2^32 - 1]. Similarly, all results are in the range [0,2^32 - 1]. Note that bit32.bnot(0) is 0xFFFFFFFF, which is different from -1.", - childs = { - arshift = { - type = "function", - description = "Returns the number x shifted disp bits to the right.\nThe number disp may be any representable integer. Negative displacements shift to the left.\nThis shift operation is what is called arithmetic shift. Vacant bits on the left are filled with copies of the higher bit of x; vacant bits on the right are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero or 0xFFFFFFFF (all original bits are shifted out).\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number, disp: number)", - returns = "(number)", - }, - band = { - type = "function", - description = "Returns the bitwise and of its operands.\nFUNCTION ADDED IN Lua 5.2.", - args = "(...)", - returns = "(number)", - }, - bnot = { - type = "function", - description = "Returns the bitwise negation of x.\nFor any integer x, the following identity holds:\nassert(bit32.bnot(x) == (-1 - x) % 2^32)\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number)", - returns = "(number)", - }, - bor = { - type = "function", - description = "Returns the bitwise or of its operands.\nFUNCTION ADDED IN Lua 5.2.", - args = "(...)", - returns = "(number)", - }, - btest = { - type = "function", - description = "Returns a boolean signaling whether the bitwise and of its operands is different from zero.\nFUNCTION ADDED IN Lua 5.2.", - args = "(...)", - returns = "(boolean)", - }, - bxor = { - type = "function", - description = "Returns the bitwise exclusive or of its operands.\nFUNCTION ADDED IN Lua 5.2.", - args = "(...)", - returns = "(number)", - }, - extract = { - type = "function", - description = "Returns the unsigned number formed by the bits field to field + width - 1 from n.\nBits are numbered from 0 (least significant) to 31 (most significant). All accessed bits must be in the range [0, 31].\nThe default for width is 1.\nFUNCTION ADDED IN Lua 5.2.", - args = "(n: number, field: number [, width: number])", - returns = "(number)", - }, - replace = { - type = "function", - description = "Returns a copy of n with the bits field to field + width - 1 replaced by the value v.\nBits are numbered from 0 (least significant) to 31 (most significant). All accessed bits must be in the range [0, 31].\nThe default for width is 1.\nFUNCTION ADDED IN Lua 5.2.", - args = "(n: number, v: number, field: number [, width: number])", - returns = "(number)", - }, - lrotate = { - type = "function", - description = "Returns the number x rotated disp bits to the left.\nThe number disp may be any representable integer.\nFor any valid displacement, the following identity holds:\nassert(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))\nIn particular, negative displacements rotate to the right.\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number, disp: number)", - returns = "(number)", - }, - lshift = { - type = "function", - description = "Returns the number x shifted disp bits to the left.\nThe number disp may be any representable integer. Negative displacements shift to the right. In any direction, vacant bits are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero (all bits are shifted out).\nFor positive displacements, the following equality holds:\nassert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number, disp: number)", - returns = "(number)", - }, - rrotate = { - type = "function", - description = "Returns the number x rotated disp bits to the right.\nThe number disp may be any representable integer.\nFor any valid displacement, the following identity holds:\nassert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))\nIn particular, negative displacements rotate to the left.\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number, disp: number)", - returns = "(number)", - }, - rshift = { - type = "function", - description = "Returns the number x shifted disp bits to the right.\nThe number disp may be any representable integer. Negative displacements shift to the left. In any direction, vacant bits are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero (all bits are shifted out).\nFor positive displacements, the following equality holds:\nassert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))\nThis shift operation is what is called logical shift.\nFUNCTION ADDED IN Lua 5.2.", - args = "(x: number, disp: number)", - returns = "(number)", - }, - }, - }, - - -- I/O library - io = { - type = "lib", - description = "The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors.\nWhen using implicit file descriptors, all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods of the file descriptor.\nThe table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr. The I/O library never closes these files.\nUnless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success.", - childs = { - stdin = { type = "value" }, - stdout = { type = "value" }, - stderr = { type = "value" }, - close = { - type = "function", - description = "Closes file. Equivalent to file:close().\nWithout a file, closes the default output file.", - args = "([file: file])", - returns = "(boolean|nil [, string, number])", - }, - flush = { - type = "function", - description = "Saves any written data to the default output file. Equivalent to io.output():flush().", - args = "()", - returns = "()", - }, - input = { - type = "function", - description = "When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file.\nIn case of errors this function raises the error, instead of returning an error code.", - args = "([file: string|file])", - returns = "([file])", - valuetype = "f", - }, - lines = { - type = "function", - description = "Opens the given file name in read mode and returns an iterator function that, each time it is called, reads the file according to the given formats.\nWhen no format is given, uses \"*l\" as a default. ARGUMENT ADDED IN Lua 5.2.\nWhen the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file.\nThe call io.lines() (with no file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends.\nIn case of errors this function raises the error, instead of returning an error code.", - args = "([filename: string, ...])", - returns = "(function)", - }, - open = { - type = "function", - description = "This function opens a file, in the mode specified in the string mode.\nIt returns a new file handle, or, in case of errors, nil plus an error message.\nThe mode string can be any of the following:\n* \"r\": read mode (the default);\n* \"w\": write mode;\n* \"a\": append mode;\n* \"r+\": update mode, all previous data is preserved;\n* \"w+\": update mode, all previous data is erased;\n* \"a+\": append update mode, previous data is preserved, writing is only allowed at the end of file.\nThe mode string can also have a 'b' at the end, which is needed in some systems to open the file in binary mode.", - args = "(filename: string [, mode: string])", - returns = "(file|nil [, string])", - valuetype = "f", - }, - output = { - type = "function", - description = "When called with a file name, it opens the named file (in text mode), and sets its handle as the default output file. When called with a file handle, it simply sets this file handle as the default output file. When called without parameters, it returns the current default output file.\nIn case of errors this function raises the error, instead of returning an error code.", - args = "([file: string|file])", - returns = "([file])", - valuetype = "f", - }, - popen = { - type = "function", - description = "Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is \"r\", the default) or to write data to this program (if mode is \"w\").\nThis function is system dependent and is not available on all platforms.", - args = "(prog: string [, mode: string])", - returns = "(file|nil [, string])", - valuetype = "f", - }, - read = { - type = "function", - description = "Reads the default input file, according to the given formats. Equivalent to io.input():read(...).", - args = "(...)", - returns = "(...)", - }, - tmpfile = { - type = "function", - description = "Returns a handle for a temporary file.\nThis file is opened in update mode and it is automatically removed when the program ends.", - args = "()", - returns = "(file)", - valuetype = "f", - }, - type = { - type = "function", - description = "Checks whether obj is a valid file handle.\nReturns the string \"file\" if obj is an open file handle, \"closed file\" if obj is a closed file handle, or nil if obj is not a file handle.", - args = "(obj: file)", - returns = "(string|nil)", - }, - write = { - type = "function", - description = "Writes the value of each of its arguments to the default output file. Equivalent to io.output():write(...).", - args = "(...)", - returns = "(file|nil [, string])", - }, - }, - }, - - f = { - type = "class", - description = "Pseudoclass for operations on file handles.", - childs = { - close = { - type = "method", - description = "Closes file.\nNote that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.\nWhen closing a file handle created with io.popen, file:close returns the same values returned by os.execute. RETURN SPECIAL CASE ADDED IN Lua 5.2.", - args = "(file: file)", - returns = "(boolean|nil [, string, number])", - }, - flush = { - type = "method", - description = "Saves any written data to file.", - args = "(file: file)", - returns = "(boolean|nil [, string])", - }, - lines = { - type = "method", - description = "Returns an iterator function that, each time it is called, reads the file according to the given formats.\nWhen no format is given, uses \"*l\" as a default. ARGUMENT ADDED IN Lua 5.2.\nUnlike io.lines, this function does not close the file when the loop ends.\nIn case of errors this function raises the error, instead of returning an error code.", - args = "(file: file, ...)", - returns = "(function)", - }, - read = { - type = "method", - description = "Reads the file file, according to the given formats, which specify what to read.\nFor each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the next line (see below).\nThe available formats are\n* \"*n\": reads a number; this is the only format that returns a number instead of a string.\n* \"*a\": reads the whole file, starting at the current position. On end of file, it returns the empty string.\n* \"*l\": reads the next line skipping the end of line, returning nil on end of file. This is the default format.\n* \"*L\": reads the next line keeping the end of line (if present), returning nil on end of file. VALUE ADDED IN Lua 5.2.\n* number: reads a string with up to this number of bytes, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.", - args = "(file: file, ...)", - returns = "(...)", - }, - seek = { - type = "method", - description = "Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence.\nThe string whence is specified as follows:\n* \"set\": base is position 0 (beginning of the file);\n* \"cur\": base is current position;\n* \"end\": base is end of file.\nIn case of success, seek returns the final file position, measured in bytes from the beginning of the file. If seek fails, it returns nil, plus a string describing the error.\nThe default value for whence is \"cur\", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek(\"set\") sets the position to the beginning of the file (and returns 0); and the call file:seek(\"end\") sets the position to the end of the file, and returns its size.", - args = "(file: file, [whence: string [, offset: number]])", - returns = "(number|nil [, string])", - }, - setvbuf = { - type = "method", - description = "Sets the buffering mode for an output file.\nThere are three available modes:\n* \"no\": no buffering; the result of any output operation appears immediately.\n* \"full\": full buffering; output operation is performed only when the buffer is full or when you explicitly flush the file (see io.flush).\n* \"line\": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).\nFor the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.", - args = "(file: file, mode: string [, size: number])", - returns = "(boolean|nil [, string])", - }, - write = { - type = "method", - description = "Writes the value of each of its arguments to file.\nThe arguments must be strings or numbers.\nIn case of success, this function returns file (RETURN CHANGED IN Lua 5.2, BOOLEAN IN LUA 5.1). Otherwise it returns nil plus a string describing the error.", - args = "(file: file, ...)", - returns = "(file|nil [, string])", - }, - }, - }, - - m = { - type = "class", - description = "Pseudoclass for metamethods.", - childs = { - __add = { - type = "function", - description = "The + operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __sub = { - type = "function", - description = "The - operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __mul = { - type = "function", - description = "The * operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __div = { - type = "function", - description = "The / operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __mod = { - type = "function", - description = "The % operation. Behavior similar to the 'add' operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __pow = { - type = "function", - description = "The ^ (exponentiation) operation. Behavior similar to the 'add' operation, with the function pow (from the C math library) as the primitive operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __concat = { - type = "function", - description = "The .. (concatenation) operation.", - args = "(op1, op2)", - returns = "(value)", - }, - __unm = { - type = "function", - description = "The unary - operation.", - args = "(op)", - returns = "(value)", - }, - __len = { - type = "function", - description = "The # (length) operation.", - args = "(op)", - returns = "(value)", - }, - __eq = { - type = "function", - description = "The == operation. A metamethod is selected only when both values being compared have the same type and the same metamethod for the selected operation, and the values are either tables or full userdata.", - args = "(op1, op2)", - returns = "(boolean)", - }, - __lt = { - type = "function", - description = "The < operation.", - args = "(op1, op2)", - returns = "(boolean)", - }, - __le = { - type = "function", - description = "The <= operation. Note that, in the absence of a 'le' metamethod, Lua tries the 'lt', assuming that a <= b is equivalent to not (b < a).", - args = "(op1, op2)", - returns = "(boolean)", - }, - __index = { - type = "function", - description = "The indexing access table[key]. Note that the metamethod is tried only when key is not present in table. When table is not a table, no key is ever present, so the metamethod is always tried.", - args = "(table, key)", - returns = "(value)", - }, - __newindex = { - type = "function", - description = "The indexing assignment table[key] = value. Note that the metamethod is tried only when key is not present in table.", - args = "(table, key, value)", - returns = "(value)", - }, - __call = { - type = "function", - description = "This method is called when Lua calls a value.", - args = "(func, ...)", - returns = "(values)", - }, - __tostring = { - type = "function", - description = "Control string representation. When the builtin 'tostring(table)' function is called, if the metatable for myTable has a __tostring property set to a function, that function is invoked (passing table to it) and the return value is used as the string representation.", - args = "(op)", - returns = "(value)", - }, - __pairs = { - type = "function", - description = "This method is called when pairs() is called and returns the first three results from the call (Lua 5.2+).", - args = "(table)", - returns = "(iterator, table, key)", - }, - __ipairs = { - type = "function", - description = "This method is called when ipairs() is called and returns the first three results from the call (Lua 5.2+).", - args = "(table)", - returns = "(iterator, table, index)", - }, - __gc = { - type = "function", - description = "Finalizer method. When userdata/table is set to be garbage collected, if the metatable has a __gc field pointing to a function, that function is first invoked, passing the userdata to it. Starting from Lua 5.2 this method is also called for tables.", - args = "(func, ...)", - returns = "(values)", - }, - __mode = { - type = "value", - description = "Value that controls 'weakness' of the table. If the __mode field is a string containing the character 'k', the keys in the table are weak. If __mode contains 'v', the values in the table are weak.", - }, - __metatable = { - type = "value", - description = "Value to hide the metatable. This value is returned as the result of getmetatable() call.", - }, - }, - }, - - -- OS library - os = { - type = "lib", - description = "This library is implemented through table os.", - childs = { - clock = { - type = "function", - description = "Returns an approximation of the amount in seconds of CPU time used by the program.", - args = "()", - returns = "(number)", - }, - date = { - type = "function", - description = "Returns a string or a table containing date and time, formatted according to the given string format.\nIf the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.\nIf format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string \"*t\", then date returns a table with the following fields: year (four digits), month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.\nIf format is not \"*t\", then date returns the date as a string, formatted according to the same rules as the C function strftime.\nWhen called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date(\"%c\")).\nOn some systems, this function may be not thread safe.", - args = "([format: string [, time: number]])", - returns = "(string|table)", - }, - difftime = { - type = "function", - description = "Returns the number of seconds from time t1 to time t2.\nIn POSIX, Windows, and some other systems, this value is exactly t2-t1.", - args = "(t2: number, t1: number)", - returns = "(number)", - }, - execute = { - type = "function", - description = "This function is equivalent to the C function system. It passes command to be executed by an operating system shell.\nRETURNS IN Lua 5.2:\nIts first result is true if the command terminated successfully, or nil otherwise. After this first result the function returns a string and a number, as follows:\n* \"exit\": the command terminated normally; the following number is the exit status of the command.\n* \"signal\": the command was terminated by a signal; the following number is the signal that terminated the command.\nWhen called without a command, os.execute returns a boolean that is true if a shell is available.\nRETURNS IN LUA 5.1:\nIt returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise.", - args = "([command: string])", - returns = "(boolean|nil [, string, number])", - }, - exit = { - type = "function", - description = "Calls the C function exit to terminate the host program.\nIf code is true, the returned status is EXIT_SUCCESS; if code is false, the returned status is EXIT_FAILURE; if code is a number, the returned status is this number. The default value for code is true. BOOLEAN VALUE ADDED IN Lua 5.2.\nIf the optional second argument close is true, closes the Lua state before exiting. ARGUMENT ADDED IN Lua 5.2.", - args = "([code: boolean|number [, close: boolean]])", - returns = "()", - }, - getenv = { - type = "function", - description = "Returns the value of the process environment variable varname, or nil if the variable is not defined.", - args = "(varname: string)", - returns = "(string|nil)", - }, - remove = { - type = "function", - description = "Deletes the file (or empty directory, on POSIX systems) with the given name.\nIf this function fails, it returns nil, plus a string describing the error and the error code.", - args = "(filename: string)", - returns = "(boolean|nil [, string, number])", - }, - rename = { - type = "function", - description = "Renames file or directory named oldname to newname.\nIf this function fails, it returns nil, plus a string describing the error and the error code.", - args = "(oldname: string, newname: string)", - returns = "(boolean|nil [, string, number])", - }, - setlocale = { - type = "function", - description = "Sets the current locale of the program.\nlocale is a system-dependent string specifying a locale; category is an optional string describing which category to change: \"all\", \"collate\", \"ctype\", \"monetary\", \"numeric\", or \"time\"; the default category is \"all\". The function returns the name of the new locale, or nil if the request cannot be honored.\nIf locale is the empty string, the current locale is set to an implementation-defined native locale. If locale is the string \"C\", the current locale is set to the standard C locale.When called with nil as the first argument, this function only returns the name of the current locale for the given category.", - args = "(locale: string [, category: string])", - returns = "(string|nil)", - }, - time = { - type = "function", - description = "Returns the current time when called without arguments, or a time representing the date and time specified by the given table.\nThis table must have fields year, month, and day, and may have fields hour (default is 12), min (default is 0), sec (default is 0), and isdst (default is nil). For a description of these fields, see the os.date function.\nThe returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the \"epoch\"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to os.date and os.difftime.", - args = "([table: table])", - returns = "(number)", - }, - tmpname = { - type = "function", - description = "Returns a string with a file name that can be used for a temporary file.\nThe file must be explicitly opened before its use and explicitly removed when no longer needed.\nOn POSIX systems, this function also creates a file with that name, to avoid security risks. (Someone else might create the file with wrong permissions in the time between getting the name and creating the file.) You still have to open the file to use it and to remove it (even if you do not use it).\nWhen possible, you may prefer to use io.tmpfile, which automatically removes the file when the program ends.", - args = "()", - returns = "(string)", - }, - }, - }, - - -- Debug library - debug = { - type = "lib", - description = "This library provides the functionality of the debug interface to Lua programs.\nYou should exert care when using this library. Several of its functions violate basic assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside; that userdata metatables cannot be changed by Lua code; that Lua programs do not crash) and therefore can compromise otherwise secure code. Moreover, some functions in this library may be slow.\nAll functions in this library are provided inside the debug table. All functions that operate over a thread have an optional first argument which is the thread to operate over. The default is always the current thread.", - childs = { - debug = { - type = "function", - description = "Enters an interactive mode with the user, running each string that the user enters.\nUsing simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.\nNote that commands for debug.debug are not lexically nested within any function and so have no direct access to local variables.", - args = "()", - returns = "()", - }, - getfenv = { - type = "function", - description = "Returns the environment of object o.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(o: any)", - returns = "(table)", - }, - gethook = { - type = "function", - description = "Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).", - args = "([thread: thread])", - returns = "(function, string, number)", - }, - getinfo = { - type = "function", - description = "Returns a table with information about a function.\nYou can give the function directly or you can give a number as the value of f, which means the function running at level f of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo (except for tail calls, which do not count on the stack); and so on. If f is a number larger than the number of active functions, then getinfo returns nil.\nThe returned table can contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. If present, the option 'L' adds a field named activelines with the table of valid lines.", - args = "([thread: thread,] f: function|number [, what: string])", - returns = "(table|nil)", - }, - getlocal = { - type = "function", - description = "This function returns the name and the value of the local variable with index local of the function at level f of the stack.\nThis function accesses not only explicit local variables, but also parameters, temporaries, etc.\nThe first parameter or local variable has index 1, and so on, until the last active variable. Negative indices refer to vararg parameters; -1 is the first vararg parameter (NEGATIVE VALUE ADDED IN Lua 5.2). The function returns nil if there is no variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)\nVariable names starting with '(' (open parentheses) represent internal variables (loop control variables, temporaries, varargs, and C function locals).\nThe parameter f may also be a function. In that case, getlocal returns only the name of function parameters. VALUE ADDED IN Lua 5.2.", - args = "([thread: thread,] f: number|function, local: number)", - returns = "(string|nil, any)", - }, - getmetatable = { - type = "function", - description = "Returns the metatable of the given value or nil if it does not have a metatable.", - args = "(value: any)", - returns = "(table|nil)", - }, - getregistry = { - type = "function", - description = "Returns the registry table.", - args = "()", - returns = "()", - }, - getupvalue = { - type = "function", - description = "This function returns the name and the value of the upvalue with index up of the function f.\nThe function returns nil if there is no upvalue with the given index.", - args = "(f: function, up: number)", - returns = "(string|nil, any)", - }, - getuservalue = { - type = "function", - description = "Returns the Lua value associated to u.\nIf u is not a userdata, returns nil.\nFUNCTION ADDED IN Lua 5.2.", - args = "(u: userdata)", - returns = "(table|nil)", - }, - setfenv = { - type = "function", - description = "Sets the environment of the given object to the given table. Returns object.\nFUNCTION DEPRECATED IN Lua 5.2.", - args = "(object: any, table: table)", - returns = "(any)", - }, - sethook = { - type = "function", - description = "Sets the given function as a hook.\nThe string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning:\n* 'c': the hook is called every time Lua calls a function;\n* 'r': the hook is called every time Lua returns from a function;\n* 'l': the hook is called every time Lua enters a new line of code.\nWith a count different from zero, the hook is called after every count instructions.\nWhen called without arguments, debug.sethook turns off the hook.\nWhen the hook is called, its first parameter is a string describing the event that has triggered its call: \"call\" (or \"tail call\"), \"return\", \"line\", and \"count\". For line events, the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level 0 is the getinfo function, and level 1 is the hook function).", - args = "([thread: thread,] hook: function, mask: string [, count: number])", - returns = "()", - }, - setlocal = { - type = "function", - description = "This function assigns the value value to the local variable with index local of the function at level level of the stack.\nThe function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable.\nSee debug.getlocal for more information about variable indices and names.", - args = "([thread: thread,] level: number, local: number, value: any)", - returns = "(string|nil)", - }, - setmetatable = { - type = "function", - description = "Sets the metatable for the given value to the given table (which can be nil).\nReturns value. RETURN ADDED IN Lua 5.2.", - args = "(value: any, table: table|nil)", - returns = "(any)", - }, - setupvalue = { - type = "function", - description = "This function assigns the value value to the upvalue with index up of the function f.\nThe function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue.", - args = "(f: function, up: number, value: any)", - returns = "(string|nil)", - }, - setuservalue = { - type = "function", - description = "Sets the given value as the Lua value associated to the given udata.\nvalue must be a table or nil; udata must be a full userdata.\nReturns udata.\nFUNCTION ADDED IN Lua 5.2.", - args = "(udata: userdata, value: table|nil)", - returns = "(userdata)", - }, - traceback = { - type = "function", - description = "If message is present but is neither a string nor nil, this function returns message without further processing. Otherwise, it returns a string with a traceback of the call stack.\nAn optional message string is appended at the beginning of the traceback. An optional level number tells at which level to start the traceback (default is 1, the function calling traceback).", - args = "([thread: thread,] [message: any [, level: number]])", - returns = "(string)", - }, - upvalueid = { - type = "function", - description = "Returns an unique identifier (as a light userdata) for the upvalue numbered n from the given function.\nThese unique identifiers allow a program to check whether different closures share upvalues. Lua closures that share an upvalue (that is, that access a same external local variable) will return identical ids for those upvalue indices.\nFUNCTION ADDED IN Lua 5.2.", - args = "(f: function, n: number)", - returns = "(userdata)", - }, - upvaluejoin = { - type = "function", - description = "Make the n1-th upvalue of the Lua closure f1 refer to the n2-th upvalue of the Lua closure f2.\nFUNCTION ADDED IN Lua 5.2.", - args = "(f1: function, n1: number, f2: function, n2: number)", - returns = "()", - }, - }, - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/love2d.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/love2d.lua deleted file mode 100644 index 4c8ee88..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/love2d.lua +++ /dev/null @@ -1,6566 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC - --- converted from love_api.lua in https://github.com/rm-code/love-api --- (API for LÖVE 0.10.0 as of Dec 23, 2015) --- Earlier versins used love_api.lua from http://love2d.org/forums/viewtopic.php?f=3&t=1796&start=50#p166908 --- the conversion script is at the bottom of this file - -local love = { - childs = { - audio = { - childs = { - DistanceModel = { - childs = { - exponent = { - description = "Exponential attenuation.", - type = "value" - }, - exponentclamped = { - description = "Exponential attenuation. Gain is clamped. In version 0.9.2 and older this is named exponent clamped.", - type = "value" - }, - inverse = { - description = "Inverse distance attenuation.", - type = "value" - }, - inverseclamped = { - description = "Inverse distance attenuation. Gain is clamped. In version 0.9.2 and older this is named inverse clamped.", - type = "value" - }, - linear = { - description = "Linear attenuation.", - type = "value" - }, - linearclamped = { - description = "Linear attenuation. Gain is clamped. In version 0.9.2 and older this is named linear clamped.", - type = "value" - }, - none = { - description = "Sources do not get attenuated.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Source = { - childs = { - getAttenuationDistances = { - args = "()", - description = "Returns the reference and maximum distance of the source.", - returns = "(ref: number, max: number)", - type = "function" - }, - getChannels = { - args = "()", - description = "Gets the number of channels in the Source. Only 1-channel (mono) Sources can use directional and positional effects.", - returns = "(channels: number)", - type = "function" - }, - getCone = { - args = "()", - description = "Gets the Source's directional volume cones. Together with Source:setDirection, the cone angles allow for the Source's volume to vary depending on its direction.", - returns = "(innerAngle: number, outerAngle: number, outerVolume: number)", - type = "function" - }, - getDirection = { - args = "()", - description = "Gets the direction of the Source.", - returns = "(x: number, y: number, z: number)", - type = "function" - }, - getDuration = { - args = "(unit: TimeUnit)", - description = "Gets the duration of the Source. For streaming Sources it may not always be sample-accurate, and may return -1 if the duration cannot be determined at all.", - returns = "(duration: number)", - type = "function" - }, - getPitch = { - args = "()", - description = "Gets the current pitch of the Source.", - returns = "(pitch: number)", - type = "function" - }, - getPosition = { - args = "()", - description = "Gets the position of the Source.", - returns = "(x: number, y: number, z: number)", - type = "function" - }, - getRolloff = { - args = "()", - description = "Returns the rolloff factor of the source.", - returns = "(rolloff: number)", - type = "function" - }, - getType = { - args = "()", - description = "Gets the type (static or stream) of the Source.", - returns = "(sourcetype: SourceType)", - type = "function" - }, - getVelocity = { - args = "()", - description = "Gets the velocity of the Source.", - returns = "(x: number, y: number, z: number)", - type = "function" - }, - getVolume = { - args = "()", - description = "Gets the current volume of the Source.", - returns = "(volume: number)", - type = "function" - }, - getVolumeLimits = { - args = "()", - description = "Returns the volume limits of the source.", - returns = "(min: number, max: number)", - type = "function" - }, - isLooping = { - args = "()", - description = "Returns whether the Source will loop.", - returns = "(loop: boolean)", - type = "function" - }, - isPaused = { - args = "()", - description = "Returns whether the Source is paused.", - returns = "(paused: boolean)", - type = "function" - }, - isPlaying = { - args = "()", - description = "Returns whether the Source is playing.", - returns = "(playing: boolean)", - type = "function" - }, - isStopped = { - args = "()", - description = "Returns whether the Source is stopped.", - returns = "(stopped: boolean)", - type = "function" - }, - pause = { - args = "()", - description = "Pauses the Source.", - returns = "()", - type = "function" - }, - play = { - args = "()", - description = "Starts playing the Source.", - returns = "(success: boolean)", - type = "function" - }, - resume = { - args = "()", - description = "Resumes a paused Source.", - returns = "()", - type = "function" - }, - rewind = { - args = "()", - description = "Rewinds a Source.", - returns = "()", - type = "function" - }, - seek = { - args = "(position: number, unit: TimeUnit)", - description = "Sets the playing position of the Source.", - returns = "()", - type = "function" - }, - setAttenuationDistances = { - args = "(ref: number, max: number)", - description = "Sets the reference and maximum distance of the source.", - returns = "()", - type = "function" - }, - setCone = { - args = "(innerAngle: number, outerAngle: number, outerVolume: number)", - description = "Sets the Source's directional volume cones. Together with Source:setDirection, the cone angles allow for the Source's volume to vary depending on its direction.", - returns = "()", - type = "function" - }, - setDirection = { - args = "(x: number, y: number, z: number)", - description = "Sets the direction vector of the Source. A zero vector makes the source non-directional.", - returns = "()", - type = "function" - }, - setLooping = { - args = "(loop: boolean)", - description = "Sets whether the Source should loop.", - returns = "()", - type = "function" - }, - setPitch = { - args = "(pitch: number)", - description = "Sets the pitch of the Source.", - returns = "()", - type = "function" - }, - setPosition = { - args = "(x: number, y: number, z: number)", - description = "Sets the position of the Source.", - returns = "()", - type = "function" - }, - setRolloff = { - args = "(rolloff: number)", - description = "Sets the rolloff factor.", - returns = "()", - type = "function" - }, - setVelocity = { - args = "(x: number, y: number, z: number)", - description = "Sets the velocity of the Source.\n\nThis does not change the position of the Source, but is used to calculate the doppler effect.", - returns = "()", - type = "function" - }, - setVolume = { - args = "(volume: number)", - description = "Sets the volume of the Source.", - returns = "()", - type = "function" - }, - setVolumeLimits = { - args = "(min: number, max: number)", - description = "Sets the volume limits of the source. The limits have to be numbers from 0 to 1.", - returns = "()", - type = "function" - }, - stop = { - args = "()", - description = "Stops a Source.", - returns = "()", - type = "function" - }, - tell = { - args = "(unit: TimeUnit)", - description = "Gets the currently playing position of the Source.", - returns = "(position: number)", - type = "function" - } - }, - description = "A Source represents audio you can play back. You can do interesting things with Sources, like set the volume, pitch, and its position relative to the listener.", - type = "lib" - }, - SourceType = { - childs = { - static = { - description = "Decode the entire sound at once.", - type = "value" - }, - stream = { - description = "Stream the sound; decode it gradually.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - TimeUnit = { - childs = { - samples = { - description = "Audio samples.", - type = "value" - }, - seconds = { - description = "Regular seconds.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - getDopplerScale = { - args = "()", - description = "Gets the current global scale factor for velocity-based doppler effects.", - returns = "(scale: number)", - type = "function" - }, - getOrientation = { - args = "()", - description = "Returns the orientation of the listener.", - returns = "(fx: number, fy: number, fz: number, ux: number, uy: number, uz: number)", - type = "function" - }, - getPosition = { - args = "()", - description = "Returns the position of the listener.", - returns = "(x: number, y: number, z: number)", - type = "function" - }, - getSourceCount = { - args = "()", - description = "Returns the number of sources which are currently playing or paused.", - returns = "(numSources: number)", - type = "function" - }, - getVelocity = { - args = "()", - description = "Returns the velocity of the listener.", - returns = "(x: number, y: number, z: number)", - type = "function" - }, - getVolume = { - args = "()", - description = "Returns the master volume.", - returns = "(volume: number)", - type = "function" - }, - newSource = { - args = "(filename: string, type: SourceType)", - description = "Creates a new Source from a file or SoundData. Sources created from SoundData are always static.", - returns = "(source: Source)", - type = "function" - }, - pause = { - args = "(source: Source)", - description = "Pauses all audio", - returns = "()", - type = "function" - }, - play = { - args = "(source: Source)", - description = "Plays the specified Source.", - returns = "()", - type = "function" - }, - resume = { - args = "(source: Source)", - description = "Resumes all audio", - returns = "()", - type = "function" - }, - rewind = { - args = "(source: Source)", - description = "Rewinds all playing audio.", - returns = "()", - type = "function" - }, - setDistanceModel = { - args = "(model: DistanceModel)", - description = "Sets the distance attenuation model.", - returns = "()", - type = "function" - }, - setDopplerScale = { - args = "(scale: number)", - description = "Sets a global scale factor for velocity-based doppler effects. The default scale value is 1.", - returns = "()", - type = "function" - }, - setOrientation = { - args = "(fx: number, fy: number, fz: number, ux: number, uy: number, uz: number)", - description = "Sets the orientation of the listener.", - returns = "()", - type = "function" - }, - setPosition = { - args = "(x: number, y: number, z: number)", - description = "Sets the position of the listener, which determines how sounds play.", - returns = "()", - type = "function" - }, - setVelocity = { - args = "(x: number, y: number, z: number)", - description = "Sets the velocity of the listener.", - returns = "()", - type = "function" - }, - setVolume = { - args = "(volume: number)", - description = "Sets the master volume.", - returns = "()", - type = "function" - }, - stop = { - args = "(source: Source)", - description = "Stops all playing audio.", - returns = "()", - type = "function" - } - }, - description = "Provides an interface to create noise with the user's speakers.", - type = "class" - }, - directorydropped = { - args = "(path: string)", - description = "Callback function triggered when a directory is dragged and dropped onto the window.", - returns = "()", - type = "function" - }, - draw = { - args = "()", - description = "Callback function used to draw on the screen every frame.", - returns = "()", - type = "function" - }, - errhand = { - args = "(msg: string)", - description = "The error handler, used to display error messages.", - returns = "()", - type = "function" - }, - event = { - childs = { - Event = { - childs = { - focus = { - description = "Window focus gained or lost", - type = "value" - }, - joystickaxis = { - description = "Joystick axis motion", - type = "value" - }, - joystickhat = { - description = "Joystick hat pressed", - type = "value" - }, - joystickpressed = { - description = "Joystick pressed", - type = "value" - }, - joystickreleased = { - description = "Joystick released", - type = "value" - }, - keypressed = { - description = "Key pressed", - type = "value" - }, - keyreleased = { - description = "Key released", - type = "value" - }, - mousefocus = { - description = "Window mouse focus gained or lost", - type = "value" - }, - mousepressed = { - description = "Mouse pressed", - type = "value" - }, - mousereleased = { - description = "Mouse released", - type = "value" - }, - quit = { - description = "Quit", - type = "value" - }, - resize = { - description = "Window size changed by the user", - type = "value" - }, - threaderror = { - description = "A Lua error has occurred in a thread.", - type = "value" - }, - visible = { - description = "Window is minimized or un-minimized by the user", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - poll = { - args = "()", - description = "Returns an iterator for messages in the event queue.", - returns = "(i: function)", - type = "function" - }, - pump = { - args = "()", - description = "Pump events into the event queue. This is a low-level function, and is usually not called by the user, but by love.run. Note that this does need to be called for any OS to think you're still running, and if you want to handle OS-generated events at all (think callbacks). love.event.pump can only be called from the main thread, but afterwards, the rest of love.event can be used from any other thread.", - returns = "()", - type = "function" - }, - push = { - args = "(e: Event, a: mixed, b: mixed, c: mixed, d: mixed)", - description = "Adds an event to the event queue.", - returns = "()", - type = "function" - }, - quit = { - args = "()", - description = "Adds the quit event to the queue.\n\nThe quit event is a signal for the event handler to close LÖVE. It's possible to abort the exit process with the love.quit callback.", - returns = "()", - type = "function" - }, - wait = { - args = "()", - description = "Like love.event.poll but blocks until there is an event in the queue.", - returns = "(e: Event, a: mixed, b: mixed, c: mixed, d: mixed)", - type = "function" - } - }, - description = "Manages events, like keypresses.", - type = "lib" - }, - filedropped = { - args = "(file: File)", - description = "Callback function triggered when a file is dragged and dropped onto the window.", - returns = "()", - type = "function" - }, - filesystem = { - childs = { - BufferMode = { - childs = { - full = { - description = "Full buffering. Write and append operations are always buffered until the buffer size limit is reached.", - type = "value" - }, - line = { - description = "Line buffering. Write and append operations are buffered until a newline is output or the buffer size limit is reached.", - type = "value" - }, - none = { - description = "No buffering. The result of write and append operations appears immediately.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - File = { - childs = { - flush = { - args = "()", - description = "Flushes any buffered written data in the file to the disk.", - returns = "(success: boolean, err: string)", - type = "function" - }, - getBuffer = { - args = "()", - description = "Gets the buffer mode of a file.", - returns = "(mode: BufferMode, size: number)", - type = "function" - }, - getMode = { - args = "()", - description = "Gets the FileMode the file has been opened with.", - returns = "(mode: FileMode)", - type = "function" - }, - getSize = { - args = "()", - description = "Returns the file size.", - returns = "(size: number)", - type = "function" - }, - isEOF = { - args = "()", - description = "Gets whether end-of-file has been reached.", - returns = "(eof: boolean)", - type = "function" - }, - isOpen = { - args = "()", - description = "Gets whether the file is open.", - returns = "(open: boolean)", - type = "function" - }, - lines = { - args = "()", - description = "Iterate over all the lines in a file", - returns = "(iterator: function)", - type = "function" - }, - open = { - args = "(mode: FileMode)", - description = "Open the file for write, read or append.\n\nIf you are getting the error message \"Could not set write directory\", try setting the save directory. This is done either with love.filesystem.setIdentity or by setting the identity field in love.conf.", - returns = "(ok: boolean)", - type = "function" - }, - read = { - args = "(bytes: number)", - description = "Read a number of bytes from a file.", - returns = "(contents: string, size: number)", - type = "function" - }, - seek = { - args = "(position: number)", - description = "Seek to a position in a file.", - returns = "(success: boolean)", - type = "function" - }, - setBuffer = { - args = "(mode: BufferMode, size: number)", - description = "Sets the buffer mode for a file opened for writing or appending. Files with buffering enabled will not write data to the disk until the buffer size limit is reached, depending on the buffer mode.", - returns = "(success: boolean, errorstr: string)", - type = "function" - }, - write = { - args = "(data: string, size: number)", - description = "Write data to a file.", - returns = "(success: boolean)", - type = "function" - } - }, - description = "Represents a file on the filesystem.", - type = "lib" - }, - FileData = { - childs = { - getFilename = { - args = "()", - description = "Gets the filename of the FileData.", - returns = "(name: string)", - type = "function" - } - }, - description = "Data representing the contents of a file.", - type = "lib" - }, - FileDecoder = { - childs = { - base64 = { - description = "The data is base64-encoded.", - type = "value" - }, - file = { - description = "The data is unencoded.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - FileMode = { - childs = { - a = { - description = "Open a file for append.", - type = "value" - }, - c = { - description = "Do not open a file (represents a closed file.)", - type = "value" - }, - r = { - description = "Open a file for read.", - type = "value" - }, - w = { - description = "Open a file for write.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - areSymlinksEnabled = { - args = "()", - description = "Gets whether love.filesystem follows symbolic links.", - returns = "(enable: boolean)", - type = "function" - }, - createDirectory = { - args = "(name: string)", - description = "Creates a directory.", - returns = "(ok: boolean)", - type = "function" - }, - exists = { - args = "(filename: string)", - description = "Check whether a file or directory exists.", - returns = "(e: boolean)", - type = "function" - }, - getAppdataDirectory = { - args = "()", - description = "Returns the application data directory (could be the same as getUserDirectory)", - returns = "(path: string)", - type = "function" - }, - getDirectoryItems = { - args = "(dir: string)", - description = "Returns a table with the names of files and subdirectories in the specified path. The table is not sorted in any way; the order is undefined.\n\nIf the path passed to the function exists in the game and the save directory, it will list the files and directories from both places.", - returns = "(items: table)", - type = "function" - }, - getIdentity = { - args = "(name: string)", - description = "Gets the write directory name for your game. Note that this only returns the name of the folder to store your files in, not the full location.", - returns = "()", - type = "function" - }, - getLastModified = { - args = "(filename: string)", - description = "Gets the last modification time of a file.", - returns = "(modtime: number, errormsg: string)", - type = "function" - }, - getRealDirectory = { - args = "(filepath: string)", - description = "Gets the platform-specific absolute path of the directory containing a filepath.\n\nThis can be used to determine whether a file is inside the save directory or the game's source .love.", - returns = "(realdir: string)", - type = "function" - }, - getRequirePath = { - args = "()", - description = "Gets the filesystem paths that will be searched when require is called.\n\nThe paths string returned by this function is a sequence of path templates separated by semicolons. The argument passed to require will be inserted in place of any question mark (\"?\") character in each template (after the dot characters in the argument passed to require are replaced by directory separators.)\n\nThe paths are relative to the game's source and save directories, as well as any paths mounted with love.filesystem.mount.", - returns = "(paths: string)", - type = "function" - }, - getSaveDirectory = { - args = "()", - description = "Gets the full path to the designated save directory. This can be useful if you want to use the standard io library (or something else) to read or write in the save directory.", - returns = "(path: string)", - type = "function" - }, - getSize = { - args = "(filename: string)", - description = "Gets the size in bytes of a file.", - returns = "(size: number, errormsg: string)", - type = "function" - }, - getSourceBaseDirectory = { - args = "()", - description = "Returns the full path to the directory containing the .love file. If the game is fused to the LÖVE executable, then the directory containing the executable is returned.\n\nIf love.filesystem.isFused is true, the path returned by this function can be passed to love.filesystem.mount, which will make the directory containing the main game readable by love.filesystem.", - returns = "(path: string)", - type = "function" - }, - getUserDirectory = { - args = "()", - description = "Returns the path of the user's directory.", - returns = "(path: string)", - type = "function" - }, - getWorkingDirectory = { - args = "()", - description = "Gets the current working directory.", - returns = "(path: string)", - type = "function" - }, - isDirectory = { - args = "(path: string)", - description = "Check whether something is a directory.", - returns = "(is_dir: boolean)", - type = "function" - }, - isFile = { - args = "(path: string)", - description = "Check whether something is a file.", - returns = "(is_file: boolean)", - type = "function" - }, - isFused = { - args = "()", - description = "Gets whether the game is in fused mode or not.\n\nIf a game is in fused mode, its save directory will be directly in the Appdata directory instead of Appdata/LOVE/. The game will also be able to load C Lua dynamic libraries which are located in the save directory.\n\nA game is in fused mode if the source .love has been fused to the executable (see Game Distribution), or if \"--fused\" has been given as a command-line argument when starting the game.", - returns = "(fused: boolean)", - type = "function" - }, - isSymlink = { - args = "(path: string)", - description = "Gets whether a filepath is actually a symbolic link.\n\nIf symbolic links are not enabled (via love.filesystem.setSymlinksEnabled), this function will always return false.", - returns = "(symlink: boolean)", - type = "function" - }, - lines = { - args = "(name: string)", - description = "Iterate over the lines in a file.", - returns = "(iterator: function)", - type = "function" - }, - load = { - args = "(name: string)", - description = "Load a file (but not run it).", - returns = "(chunk: function)", - type = "function" - }, - mount = { - args = "(archive: string, mountpoint: string)", - description = "Mounts a zip file or folder in the game's save directory for reading.", - returns = "(success: boolean)", - type = "function" - }, - newFile = { - args = "(filename: string, mode: FileMode)", - description = "Creates a new File object. It needs to be opened before it can be accessed.", - returns = "(file: File, errorstr: string)", - type = "function" - }, - newFileData = { - args = "(contents: string, name: string, decoder: FileDecoder)", - description = "Creates a new FileData object.", - returns = "(data: FileData)", - type = "function" - }, - read = { - args = "(name: string, bytes: number)", - description = "Read the contents of a file.", - returns = "(contents: string, size: number)", - type = "function" - }, - remove = { - args = "(name: string)", - description = "Removes a file or directory.", - returns = "(ok: boolean)", - type = "function" - }, - setIdentity = { - args = "(name: string, searchorder: SearchOrder)", - description = "Sets the write directory for your game. Note that you can only set the name of the folder to store your files in, not the location.", - returns = "()", - type = "function" - }, - setRequirePath = { - args = "(paths: string)", - description = "Sets the filesystem paths that will be searched when require is called.\n\nThe paths string given to this function is a sequence of path templates separated by semicolons. The argument passed to require will be inserted in place of any question mark (\"?\") character in each template (after the dot characters in the argument passed to require are replaced by directory separators.)\n\nThe paths are relative to the game's source and save directories, as well as any paths mounted with love.filesystem.mount.", - returns = "()", - type = "function" - }, - setSource = { - args = "(path: string)", - description = "Sets the source of the game, where the code is present. This function can only be called once, and is normally automatically done by LÖVE.", - returns = "()", - type = "function" - }, - setSymlinksEnabled = { - args = "(enable: boolean)", - description = "Sets whether love.filesystem follows symbolic links. Sets whether love.filesystem follows symbolic links. It is enabled by default in version 0.10.0 and newer, and disabled by default in 0.9.2.", - returns = "()", - type = "function" - }, - unmount = { - args = "(archive: string)", - description = "Unmounts a zip file or folder previously mounted for reading with love.filesystem.mount.", - returns = "(success: boolean)", - type = "function" - }, - write = { - args = "(name: string, data: string, size: number)", - description = "Write data to a file.\n\nIf you are getting the error message \"Could not set write directory\", try setting the save directory. This is done either with love.filesystem.setIdentity or by setting the identity field in love.conf.", - returns = "(success: boolean)", - type = "function" - } - }, - description = "Provides an interface to the user's filesystem.", - type = "class" - }, - focus = { - args = "(f: boolean)", - description = "Callback function triggered when window receives or loses focus.", - returns = "()", - type = "function" - }, - gamepadaxis = { - args = "(joystick: Joystick, axis: GamepadAxis)", - description = "Called when a Joystick's virtual gamepad axis is moved.", - returns = "()", - type = "function" - }, - gamepadpressed = { - args = "(joystick: Joystick, button: GamepadButton)", - description = "Called when a Joystick's virtual gamepad button is pressed.", - returns = "()", - type = "function" - }, - gamepadreleased = { - args = "(joystick: Joystick, button: GamepadButton)", - description = "Called when a Joystick's virtual gamepad button is released.", - returns = "()", - type = "function" - }, - getVersion = { - args = "()", - description = "Gets the current running version of LÖVE.", - returns = "(major: number, minor: number, revision: number, codename: string)", - type = "function" - }, - graphics = { - childs = { - AlignMode = { - childs = { - center = { - description = "Align text center.", - type = "value" - }, - left = { - description = "Align text left.", - type = "value" - }, - right = { - description = "Align text right.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - AreaSpreadDistribution = { - childs = { - none = { - description = "No distribution - area spread is disabled.", - type = "value" - }, - normal = { - description = "Normal (gaussian) distribution.", - type = "value" - }, - uniform = { - description = "Uniform distribution.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - BlendMode = { - childs = { - add = { - description = "The pixel colors of what's drawn are added to the pixel colors already on the screen. The alpha of the screen is not modified.", - type = "value" - }, - alpha = { - description = "Alpha blending (normal). The alpha of what's drawn determines its opacity.", - type = "value" - }, - multiply = { - description = "The pixel colors of what's drawn are multiplied with the pixel colors already on the screen (darkening them). The alpha of drawn objects is multiplied with the alpha of the screen rather than determining how much the colors on the screen are affected, even when the \"alphamultiply\" BlendAlphaMode is used.", - type = "value" - }, - replace = { - description = "The colors of what's drawn completely replace what was on the screen, with no additional blending.", - type = "value" - }, - screen = { - description = "\"Screen\" blending.", - type = "value" - }, - subtract = { - description = "The pixel colors of what's drawn are subtracted from the pixel colors already on the screen. The alpha of the screen is not modified.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Canvas = { - childs = { - getFilter = { - args = "()", - description = "Gets the filter mode of the Canvas.", - returns = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - type = "function" - }, - getFormat = { - args = "()", - description = "Gets the texture format of the Canvas.", - returns = "(format: CanvasFormat)", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the Canvas.", - returns = "(height: number)", - type = "function" - }, - getMSAA = { - args = "()", - description = "Gets the number of multisample antialiasing (MSAA) samples used when drawing to the Canvas.\n\nThis may be different than the number used as an argument to love.graphics.newCanvas if the system running LÖVE doesn't support that number.", - returns = "(samples: number)", - type = "function" - }, - getWidth = { - args = "()", - description = "Gets the width of the Canvas.", - returns = "(width: number)", - type = "function" - }, - getWrap = { - args = "()", - description = "Gets the wrapping properties of a Canvas.\n\nThis function returns the currently set horizontal and vertical wrapping modes for the Canvas.", - returns = "(horizontal: WrapMode, vertical: WrapMode)", - type = "function" - }, - isActive = { - args = "()", - description = "Gets whether the graphics module is able to be used. If it is not active, love.graphics function and method calls will not work correctly and may cause the program to crash. The graphics module is inactive if a window is not open, or if the app is in the background on iOS. Typically the app's execution will be automatically paused by the system, in the latter case.", - returns = "()", - type = "function" - }, - newImageData = { - args = "(x: number, y: number, width: number, height: number)", - description = "Generates ImageData from the contents of the Canvas.", - returns = "(data: ImageData)", - type = "function" - }, - renderTo = { - args = "(func: function)", - description = "Render to the Canvas using a function.", - returns = "()", - type = "function" - }, - setFilter = { - args = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - description = "Sets the filter of the Canvas.", - returns = "()", - type = "function" - }, - setWrap = { - args = "(horizontal: WrapMode, vertical: WrapMode)", - description = "Sets the wrapping properties of a Canvas.\n\nThis function sets the way the edges of a Canvas are treated if it is scaled or rotated. If the WrapMode is set to \"clamp\", the edge will not be interpolated. If set to \"repeat\", the edge will be interpolated with the pixels on the opposing side of the framebuffer.", - returns = "()", - type = "function" - } - }, - description = "A Canvas is used for off-screen rendering. Think of it as an invisible screen that you can draw to, but that will not be visible until you draw it to the actual visible screen. It is also known as \"render to texture\".\n\nBy drawing things that do not change position often (such as background items) to the Canvas, and then drawing the entire Canvas instead of each item, you can reduce the number of draw operations performed each frame.", - type = "lib" - }, - CanvasFormat = { - childs = { - hdr = { - description = "A format suitable for high dynamic range content - an alias for the rgba16f format, normally.", - type = "value" - }, - normal = { - description = "The default Canvas format - usually an alias for the rgba8 format, or the srgb format if gamma-correct rendering is enabled in LÖVE 0.10.0 and newer.", - type = "value" - }, - r8 = { - description = "Single-channel (red component) format (8 bpp.)", - type = "value" - }, - r16f = { - description = "Floating point single-channel format (16 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - r32f = { - description = "Floating point single-channel format (32 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - rg8 = { - description = "Two channels (red and green components) with 8 bits per channel (16 bpp.)", - type = "value" - }, - rg11b10f = { - description = "Floating point RGB with 11 bits in the red and green channels, and 10 bits in the blue channel (32 bpp.) There is no alpha channel. Color values can range from [0, +65024].", - type = "value" - }, - rg16f = { - description = "Floating point two-channel format with 16 bits per channel (32 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - rg32f = { - description = "Floating point two-channel format with 32 bits per channel (64 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - rgb5a1 = { - description = "RGB with 5 bits each, and a 1-bit alpha channel (16 bpp.)", - type = "value" - }, - rgb10a2 = { - description = "RGB with 10 bits per channel, and a 2-bit alpha channel (32 bpp.)", - type = "value" - }, - rgb565 = { - description = "RGB with 5, 6, and 5 bits each, respectively (16 bpp). There is no alpha channel in this format.", - type = "value" - }, - rgba4 = { - description = "4 bits per channel (16 bpp) RGBA.", - type = "value" - }, - rgba8 = { - description = "8 bits per channel (32 bpp) RGBA. Color channel values range from 0-255 (0-1 in shaders.)", - type = "value" - }, - rgba16f = { - description = "Floating point RGBA with 16 bits per channel (64 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - rgba32f = { - description = "Floating point RGBA with 32 bits per channel (128 bpp.) Color values can range from [-65504, +65504].", - type = "value" - }, - srgb = { - description = "The same as rgba8, but the Canvas is interpreted as being in the sRGB color space. Everything drawn to the Canvas will be converted from linear RGB to sRGB. When the Canvas is drawn (or used in a shader), it will be decoded from sRGB to linear RGB. This reduces color banding when doing gamma-correct rendering, since sRGB encoding has more precision than linear RGB for darker colors.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - DrawMode = { - childs = { - fill = { - description = "Draw filled shape.", - type = "value" - }, - line = { - description = "Draw outlined shape.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - FilterMode = { - childs = { - linear = { - description = "Scale image with linear interpolation.", - type = "value" - }, - nearest = { - description = "Scale image with nearest neighbor interpolation.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Font = { - childs = { - getBaseline = { - args = "()", - description = "Gets the baseline of the Font. Most scripts share the notion of a baseline: an imaginary horizontal line on which characters rest. In some scripts, parts of glyphs lie below the baseline.", - returns = "(baseline: number)", - type = "function" - }, - getDescent = { - args = "()", - description = "Gets the descent of the Font. The descent spans the distance between the baseline and the lowest descending glyph in a typeface.", - returns = "(descent: number)", - type = "function" - }, - getFilter = { - args = "()", - description = "Gets the filter mode for a font.", - returns = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the Font. The height of the font is the size including any spacing; the height which it will need.", - returns = "(height: number)", - type = "function" - }, - getLineHeight = { - args = "()", - description = "Gets the line height. This will be the value previously set by Font:setLineHeight, or 1.0 by default.", - returns = "(height: number)", - type = "function" - }, - getWidth = { - args = "(line: string)", - description = "Determines the horizontal size a line of text needs. Does not support line-breaks.", - returns = "(width: number)", - type = "function" - }, - getWrap = { - args = "(text: string, wraplimit: number)", - description = "Gets formatting information for text, given a wrap limit.\n\nThis function accounts for newlines correctly (i.e. '\\n').", - returns = "(width: number, wrappedtext: table)", - type = "function" - }, - hasGlyph = { - args = "(character: string)", - description = "Gets whether the font can render a particular character.", - returns = "(hasglyph: boolean)", - type = "function" - }, - setFallbacks = { - args = "(fallbackfont1: Font, ...: Font)", - description = "Sets other Fonts to use if this Font doesn't have a specific character. When that happens, the glyph from the first fallback Font to have the character will be used, instead of a blank box or other 'no character' symbol being used.", - returns = "()", - type = "function" - }, - setFilter = { - args = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - description = "Sets the filter mode for a font.", - returns = "()", - type = "function" - }, - setLineHeight = { - args = "(height: number)", - description = "Sets the line height. When rendering the font in lines the actual height will be determined by the line height multiplied by the height of the font. The default is 1.0.", - returns = "()", - type = "function" - } - }, - description = "Defines the shape of characters than can be drawn onto the screen.", - type = "lib" - }, - GraphicsFeature = { - childs = { - clampzero = { - description = "Whether the \"clampzero\" WrapMode is supported.", - type = "value" - }, - multicanvasformats = { - description = "Whether multiple Canvases with different formats can be used in the same love.graphics.setCanvas call.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - GraphicsLimit = { - childs = { - canvasmsaa = { - description = "The maximum number of antialiasing samples for a Canvas.", - type = "value" - }, - multicanvas = { - description = "The maximum number of simultaneously active canvases (via love.graphics.setCanvas).", - type = "value" - }, - pointsize = { - description = "The maximum size of points.", - type = "value" - }, - texturesize = { - description = "The maximum width or height of Images and Canvases.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Image = { - childs = { - getDimensions = { - args = "()", - description = "Gets the width and height of the Image.", - returns = "(width: number, height: number)", - type = "function" - }, - getFilter = { - args = "()", - description = "Gets the filter mode for an image.", - returns = "(min: FilterMode, mag: FilterMode)", - type = "function" - }, - getFlags = { - args = "()", - description = "Gets the flags used when the image was created.", - returns = "()", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the Image.", - returns = "(height: number)", - type = "function" - }, - getMipmapFilter = { - args = "()", - description = "Gets the mipmap filter mode for an Image.", - returns = "(mode: FilterMode, sharpness: number)", - type = "function" - }, - getWidth = { - args = "()", - description = "Gets the width of the Image.", - returns = "(width: number)", - type = "function" - }, - getWrap = { - args = "()", - description = "Gets the wrapping properties of an Image.\n\nThis function returns the currently set horizontal and vertical wrapping modes for the image.", - returns = "(horizontal: WrapMode, vertical: WrapMode)", - type = "function" - }, - refresh = { - args = "(x: number, y: number, width: number, height: number)", - description = "Reloads the Image's contents from the ImageData or CompressedData used to create the image.", - returns = "()", - type = "function" - }, - setFilter = { - args = "(min: FilterMode, mag: FilterMode)", - description = "Sets the filter mode for an image.", - returns = "()", - type = "function" - }, - setMipmapFilter = { - args = "(filtermode: FilterMode, sharpness: number)", - description = "Sets the mipmap filter mode for an Image.\n\nMipmapping is useful when drawing an image at a reduced scale. It can improve performance and reduce aliasing issues.\n\nIn 0.10.0 and newer, the Image must be created with the mipmaps flag enabled for the mipmap filter to have any effect.", - returns = "()", - type = "function" - }, - setWrap = { - args = "(horizontal: WrapMode, vertical: WrapMode)", - description = "Sets the wrapping properties of an Image.\n\nThis function sets the way an Image is repeated when it is drawn with a Quad that is larger than the image's extent. An image may be clamped or set to repeat in both horizontal and vertical directions. Clamped images appear only once, but repeated ones repeat as many times as there is room in the Quad.\n\nIf you use a Quad that is larger than the image extent and do not use repeated tiling, there may be an unwanted visual effect of the image stretching all the way to fill the Quad. If this is the case, setting Image:getWrap(\"repeat\", \"repeat\") for all the images to be repeated, and using Quad of appropriate size will result in the best visual appearance.", - returns = "()", - type = "function" - } - }, - description = "Drawable image type.", - type = "lib" - }, - LineJoin = { - childs = { - bevel = { - description = "Bevel style.", - type = "value" - }, - miter = { - description = "Miter style.", - type = "value" - }, - none = { - description = "None style.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - LineStyle = { - childs = { - rough = { - description = "Draw rough lines.", - type = "value" - }, - smooth = { - description = "Draw smooth lines.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Mesh = { - childs = { - getDrawMode = { - args = "()", - description = "Gets the mode used when drawing the Mesh.", - returns = "(mode: MeshDrawMode)", - type = "function" - }, - getDrawRange = { - args = "()", - description = "Gets the range of vertices used when drawing the Mesh.\n\nIf the Mesh's draw range has not been set previously with Mesh:setDrawRange, this function will return nil.", - returns = "(min: number, max: number)", - type = "function" - }, - getTexture = { - args = "()", - description = "Gets the texture (Image or Canvas) used when drawing the Mesh.", - returns = "(texture: Texture)", - type = "function" - }, - getVertex = { - args = "(index: number)", - description = "Gets the properties of a vertex in the Mesh.", - returns = "(attributecomponent: number, ...: number)", - type = "function" - }, - getVertexAttribute = { - args = "(vertexindex: number, attributeindex: number)", - description = "Gets the properties of a specific attribute within a vertex in the Mesh.\n\nMeshes without a custom vertex format specified in love.graphics.newMesh have position as their first attribute, texture coordinates as their second attribute, and color as their third attribute.", - returns = "(value1: number, value2: number, ...: number)", - type = "function" - }, - getVertexCount = { - args = "()", - description = "Returns the total number of vertices in the Mesh.", - returns = "(num: number)", - type = "function" - }, - getVertexFormat = { - args = "()", - description = "Gets the vertex format that the Mesh was created with.", - returns = "(format: table)", - type = "function" - }, - getVertexMap = { - args = "()", - description = "Gets the vertex map for the Mesh. The vertex map describes the order in which the vertices are used when the Mesh is drawn. The vertices, vertex map, and mesh draw mode work together to determine what exactly is displayed on the screen.\n\nIf no vertex map has been set previously via Mesh:setVertexMap, then this function will return nil in LÖVE 0.10.0+, or an empty table in 0.9.2 and older.", - returns = "(vertex_map: table)", - type = "function" - }, - isAttributeEnabled = { - args = "(name: string)", - description = "Gets whether a specific vertex attribute in the Mesh is enabled. Vertex data from disabled attributes is not used when drawing the Mesh.", - returns = "(enabled: boolean)", - type = "function" - }, - setAttributeEnabled = { - args = "(name: string, enable: boolean)", - description = "Enables or disables a specific vertex attribute in the Mesh. Vertex data from disabled attributes is not used when drawing the Mesh.", - returns = "()", - type = "function" - }, - setDrawMode = { - args = "(mode: MeshDrawMode)", - description = "Sets the mode used when drawing the Mesh.", - returns = "()", - type = "function" - }, - setDrawRange = { - args = "(min: number, max: number)", - description = "Restricts the drawn vertices of the Mesh to a subset of the total.\n\nIf a vertex map is used with the Mesh, this method will set a subset of the values in the vertex map array to use, instead of a subset of the total vertices in the Mesh.\n\nFor example, if Mesh:setVertexMap(1, 2, 3, 1, 3, 4) and Mesh:setDrawRange(4, 6) are called, vertices 1, 3, and 4 will be drawn.", - returns = "()", - type = "function" - }, - setTexture = { - args = "(texture: Texture)", - description = "Sets the texture (Image or Canvas) used when drawing the Mesh.\n\nWhen called without an argument disables the texture. Untextured meshes have a white color by default.", - returns = "()", - type = "function" - }, - setVertex = { - args = "(index: number, attributecomponent: number, ...: number)", - description = "Sets the properties of a vertex in the Mesh.", - returns = "()", - type = "function" - }, - setVertexAttribute = { - args = "(vertexindex: number, attributeindex: number, value1: number, value2: number, ...: number)", - description = "Sets the properties of a specific attribute within a vertex in the Mesh.\n\nMeshes without a custom vertex format specified in love.graphics.newMesh have position as their first attribute, texture coordinates as their second attribute, and color as their third attribute.", - returns = "()", - type = "function" - }, - setVertexColors = { - args = "(on: boolean)", - description = "Sets if the per-vertex colors are used when rendering instead of the constant color (constant color being love.graphics.setColor or SpriteBatch:setColor)\n\nThe per-vertex colors are automatically enabled by default when making a new Mesh or when doing Mesh:setVertex, but only if at least one vertex color is not the default (255,255,255,255).", - returns = "()", - type = "function" - }, - setVertexMap = { - args = "(vertex_map: table)", - description = "Sets the vertex map for a Mesh. The vertex map describes the order in which the vertices are used when the Mesh is drawn.\n\nThe vertex map allows you to re-order or reuse vertices when drawing without changing the actual vertex parameters or duplicating vertices. It is especially useful when combined with different Mesh draw modes.", - returns = "()", - type = "function" - }, - setVertices = { - args = "(vertices: table, startvertex: number)", - description = "Replaces all vertices in the Mesh with new ones.", - returns = "()", - type = "function" - } - }, - description = "A 2D polygon mesh used for drawing arbitrary textured shapes.", - type = "lib" - }, - MeshDrawMode = { - childs = { - fan = { - description = "The vertices create a \"fan\" shape with the first vertex acting as the hub point. Can be easily used to draw simple convex polygons.", - type = "value" - }, - points = { - description = "The vertices are drawn as unconnected points (see love.graphics.setPointSize.)", - type = "value" - }, - strip = { - description = "The vertices create a series of connected triangles using vertices 1, 2, 3, then 3, 2, 4 (note the order), then 3, 4, 5 and so on.", - type = "value" - }, - triangles = { - description = "The vertices create unconnected triangles.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - ParticleInsertMode = { - childs = { - bottom = { - description = "Particles are inserted at the bottom of the ParticleSystem's list of particles.", - type = "value" - }, - random = { - description = "Particles are inserted at random positions in the ParticleSystem's list of particles.", - type = "value" - }, - top = { - description = "Particles are inserted at the top of the ParticleSystem's list of particles.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - ParticleSystem = { - childs = { - emit = { - args = "(numparticles: number)", - description = "Emits a burst of particles from the particle emitter.", - returns = "()", - type = "function" - }, - getAreaSpread = { - args = "()", - description = "Gets the area-based spawn parameters for the particles.", - returns = "(distribution: AreaSpreadDistribution, dx: number, dy: number)", - type = "function" - }, - getBufferSize = { - args = "()", - description = "Gets the size of the buffer (the max allowed amount of particles in the system).", - returns = "(buffer: number)", - type = "function" - }, - getColors = { - args = "()", - description = "Gets a series of colors to apply to the particle sprite. The particle system will interpolate between each color evenly over the particle's lifetime. Color modulation needs to be activated for this function to have any effect.\n\nArguments are passed in groups of four, representing the components of the desired RGBA value. At least one color must be specified. A maximum of eight may be used.", - returns = "(r1: number, g1: number, b1: number, a1: number, r2: number, g2: number, b2: number, a2: number, ...: number)", - type = "function" - }, - getCount = { - args = "()", - description = "Gets the amount of particles that are currently in the system.", - returns = "(count: number)", - type = "function" - }, - getDirection = { - args = "()", - description = "Gets the direction the particles will be emitted in.", - returns = "(direction: number)", - type = "function" - }, - getEmissionRate = { - args = "()", - description = "Gets the amount of particles emitted per second.", - returns = "(rate: number)", - type = "function" - }, - getEmitterLifetime = { - args = "()", - description = "Gets how long the particle system should emit particles (if -1 then it emits particles forever).", - returns = "(life: number)", - type = "function" - }, - getInsertMode = { - args = "()", - description = "Gets the mode to use when the ParticleSystem adds new particles.", - returns = "(mode: ParticleInsertMode)", - type = "function" - }, - getLinearAcceleration = { - args = "()", - description = "Gets the linear acceleration (acceleration along the x and y axes) for particles.\n\nEvery particle created will accelerate along the x and y axes between xmin,ymin and xmax,ymax.", - returns = "(xmin: number, ymin: number, xmax: number, ymax: number)", - type = "function" - }, - getLinearDamping = { - args = "()", - description = "Gets the amount of linear damping (constant deceleration) for particles.", - returns = "(min: number, max: number)", - type = "function" - }, - getOffset = { - args = "()", - description = "Get the offget position which the particle sprite is rotated around. If this function is not used, the particles rotate around their center.", - returns = "(x: number, y: number)", - type = "function" - }, - getParticleLifetime = { - args = "()", - description = "Gets the life of the particles.", - returns = "(min: number, max: number)", - type = "function" - }, - getPosition = { - args = "()", - description = "Gets the position of the emitter.", - returns = "(x: number, y: number)", - type = "function" - }, - getRadialAcceleration = { - args = "()", - description = "Get the radial acceleration (away from the emitter).", - returns = "(min: number, max: number)", - type = "function" - }, - getRotation = { - args = "()", - description = "Gets the rotation of the image upon particle creation (in radians).", - returns = "(min: number, max: number)", - type = "function" - }, - getSizeVariation = { - args = "()", - description = "Gets the degree of variation (0 meaning no variation and 1 meaning full variation between start and end).", - returns = "(variation: number)", - type = "function" - }, - getSizes = { - args = "()", - description = "Gets a series of sizes by which to scale a particle sprite. 1.0 is normal size. The particle system will interpolate between each size evenly over the particle's lifetime.\n\nAt least one size must be specified. A maximum of eight may be used.", - returns = "(size1: number, size2: number, ...: number)", - type = "function" - }, - getSpeed = { - args = "()", - description = "Gets the speed of the particles.", - returns = "(min: number, max: number)", - type = "function" - }, - getSpin = { - args = "()", - description = "Gets the spin of the sprite.", - returns = "(min: number, max: number)", - type = "function" - }, - getSpinVariation = { - args = "()", - description = "Gets the degree of variation (0 meaning no variation and 1 meaning full variation between start and end).", - returns = "(variation: number)", - type = "function" - }, - getSpread = { - args = "()", - description = "Gets the amount of spread for the system.", - returns = "(spread: number)", - type = "function" - }, - getTangentialAcceleration = { - args = "()", - description = "Gets the tangential acceleration (acceleration perpendicular to the particle's direction).", - returns = "(min: number, max: number)", - type = "function" - }, - getTexture = { - args = "()", - description = "Gets the Image or Canvas which is to be emitted.", - returns = "(texture: Texture)", - type = "function" - }, - hasRelativeRotation = { - args = "()", - description = "Gets whether particle angles and rotations are relative to their velocities. If enabled, particles are aligned to the angle of their velocities and rotate relative to that angle.", - returns = "(enabled: boolean)", - type = "function" - }, - isActive = { - args = "()", - description = "Checks whether the particle system is actively emitting particles.", - returns = "(active: boolean)", - type = "function" - }, - isPaused = { - args = "()", - description = "Checks whether the particle system is paused.", - returns = "(paused: boolean)", - type = "function" - }, - isStopped = { - args = "()", - description = "Checks whether the particle system is stopped.", - returns = "(stopped: boolean)", - type = "function" - }, - moveTo = { - args = "(x: number, y: number)", - description = "Moves the position of the emitter. This results in smoother particle spawning behaviour than if ParticleSystem:setPosition is used every frame.", - returns = "()", - type = "function" - }, - pause = { - args = "()", - description = "Pauses the particle emitter.", - returns = "()", - type = "function" - }, - reset = { - args = "()", - description = "Resets the particle emitter, removing any existing particles and resetting the lifetime counter.", - returns = "()", - type = "function" - }, - setAreaSpread = { - args = "(distribution: AreaSpreadDistribution, dx: number, dy: number)", - description = "Sets area-based spawn parameters for the particles. Newly created particles will spawn in an area around the emitter based on the parameters to this function.", - returns = "()", - type = "function" - }, - setBufferSize = { - args = "(buffer: number)", - description = "Sets the size of the buffer (the max allowed amount of particles in the system).", - returns = "()", - type = "function" - }, - setColors = { - args = "(r1: number, g1: number, b1: number, a1: number, r2: number, g2: number, b2: number, a2: number, ...: number)", - description = "Sets a series of colors to apply to the particle sprite. The particle system will interpolate between each color evenly over the particle's lifetime. Color modulation needs to be activated for this function to have any effect.\n\nArguments are passed in groups of four, representing the components of the desired RGBA value. At least one color must be specified. A maximum of eight may be used.", - returns = "()", - type = "function" - }, - setDirection = { - args = "(direction: number)", - description = "Sets the direction the particles will be emitted in.", - returns = "()", - type = "function" - }, - setEmissionRate = { - args = "(rate: number)", - description = "Sets the amount of particles emitted per second.", - returns = "()", - type = "function" - }, - setEmitterLifetime = { - args = "(life: number)", - description = "Sets how long the particle system should emit particles (if -1 then it emits particles forever).", - returns = "()", - type = "function" - }, - setInsertMode = { - args = "(mode: ParticleInsertMode)", - description = "Sets the mode to use when the ParticleSystem adds new particles.", - returns = "()", - type = "function" - }, - setLinearAcceleration = { - args = "(xmin: number, ymin: number, xmax: number, ymax: number)", - description = "Sets the linear acceleration (acceleration along the x and y axes) for particles.\n\nEvery particle created will accelerate along the x and y axes between xmin,ymin and xmax,ymax.", - returns = "()", - type = "function" - }, - setLinearDamping = { - args = "(min: number, max: number)", - description = "Sets the amount of linear damping (constant deceleration) for particles.", - returns = "()", - type = "function" - }, - setOffset = { - args = "(x: number, y: number)", - description = "Set the offset position which the particle sprite is rotated around. If this function is not used, the particles rotate around their center.", - returns = "()", - type = "function" - }, - setParticleLifetime = { - args = "(min: number, max: number)", - description = "Sets the life of the particles.", - returns = "()", - type = "function" - }, - setPosition = { - args = "(x: number, y: number)", - description = "Sets the position of the emitter.", - returns = "()", - type = "function" - }, - setQuads = { - args = "(quad1: Quad, quad2: Quad)", - description = "Sets a series of Quads to use for the particle sprites. Particles will choose a Quad from the list based on the particle's current lifetime, allowing for the use of animated sprite sheets with ParticleSystems.", - returns = "()", - type = "function" - }, - setRadialAcceleration = { - args = "(min: number, max: number)", - description = "Set the radial acceleration (away from the emitter).", - returns = "()", - type = "function" - }, - setRelativeRotation = { - args = "(enable: boolean)", - description = "Sets whether particle angles and rotations are relative to their velocities. If enabled, particles are aligned to the angle of their velocities and rotate relative to that angle.", - returns = "()", - type = "function" - }, - setRotation = { - args = "(min: number, max: number)", - description = "Sets the rotation of the image upon particle creation (in radians).", - returns = "()", - type = "function" - }, - setSizeVariation = { - args = "(variation: number)", - description = "Sets the degree of variation (0 meaning no variation and 1 meaning full variation between start and end).", - returns = "()", - type = "function" - }, - setSizes = { - args = "(size1: number, size2: number, ...: number)", - description = "Sets a series of sizes by which to scale a particle sprite. 1.0 is normal size. The particle system will interpolate between each size evenly over the particle's lifetime.\n\nAt least one size must be specified. A maximum of eight may be used.", - returns = "()", - type = "function" - }, - setSpeed = { - args = "(min: number, max: number)", - description = "Sets the speed of the particles.", - returns = "()", - type = "function" - }, - setSpin = { - args = "(min: number, max: number)", - description = "Sets the spin of the sprite.", - returns = "()", - type = "function" - }, - setSpinVariation = { - args = "(variation: number)", - description = "Sets the degree of variation (0 meaning no variation and 1 meaning full variation between start and end).", - returns = "()", - type = "function" - }, - setSpread = { - args = "(spread: number)", - description = "Sets the amount of spread for the system.", - returns = "()", - type = "function" - }, - setTangentialAcceleration = { - args = "(min: number, max: number)", - description = "Sets the tangential acceleration (acceleration perpendicular to the particle's direction).", - returns = "()", - type = "function" - }, - setTexture = { - args = "(texture: Texture)", - description = "Sets the Image or Canvas which is to be emitted.", - returns = "()", - type = "function" - }, - start = { - args = "()", - description = "Starts the particle emitter.", - returns = "()", - type = "function" - }, - stop = { - args = "()", - description = "Stops the particle emitter, resetting the lifetime counter.", - returns = "()", - type = "function" - }, - update = { - args = "(dt: number)", - description = "Updates the particle system; moving, creating and killing particles.", - returns = "()", - type = "function" - } - }, - description = "Used to create cool effects, like fire. The particle systems are created and drawn on the screen using functions in love.graphics. They also need to be updated in the update(dt) callback for you to see any changes in the particles emitted.", - type = "lib" - }, - PointStyle = { - childs = { - rough = { - description = "Draw rough points.", - type = "value" - }, - smooth = { - description = "Draw smooth points.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Quad = { - childs = { - setViewport = { - args = "()", - description = "Sets the texture coordinates according to a viewport.", - returns = "(x: number, y: number, w: number, h: number)", - type = "function" - } - }, - description = "A quadrilateral (a polygon with four sides and four corners) with texture coordinate information.\n\nQuads can be used to select part of a texture to draw. In this way, one large texture atlas can be loaded, and then split up into sub-images.", - type = "lib" - }, - Shader = { - childs = { - getWarnings = { - args = "()", - description = "Returns any warning and error messages from compiling the shader code. This can be used for debugging your shaders if there's anything the graphics hardware doesn't like.", - returns = "(warnings: string)", - type = "function" - }, - send = { - args = "(name: string, number: number, ...: number)", - description = "Sends one or more values to a special (extern) variable inside the shader.", - returns = "()", - type = "function" - }, - sendColor = { - args = "(name: string, color: table, ...: table)", - description = "Sends one or more colors to a special (extern / uniform) vec3 or vec4 variable inside the shader. The color components must be in the range of [0, 255], unlike Shader:send. The colors are gamma-corrected if global gamma-correction is enabled.", - returns = "()", - type = "function" - } - }, - description = "A Shader is used for advanced hardware-accelerated pixel or vertex manipulation. These effects are written in a language based on GLSL (OpenGL Shading Language) with a few things simplified for easier coding.\n\nPotential uses for pixel effects include HDR/bloom, motion blur, grayscale/invert/sepia/any kind of color effect, reflection/refraction, distortions, and much more!", - type = "lib" - }, - SpriteBatch = { - childs = { - attachAttribute = { - args = "(name: string, mesh: Mesh)", - description = "Attaches a per-vertex attribute from a Mesh onto this SpriteBatch, for use when drawing. This can be combined with a Shader to augment a SpriteBatch with per-vertex or additional per-sprite information instead of just having per-sprite colors.\n\nEach sprite in a SpriteBatch has 4 vertices in the following order: top-left, bottom-left, top-right, bottom-right. The index returned by SpriteBatch:add (and used by SpriteBatch:set) can be multiplied by 4 to determine the first vertex in a specific sprite.", - returns = "()", - type = "function" - }, - clear = { - args = "()", - description = "Removes all sprites from the buffer.", - returns = "()", - type = "function" - }, - flush = { - args = "()", - description = "Immediately sends all new and modified sprite data in the batch to the graphics card.", - returns = "()", - type = "function" - }, - getBufferSize = { - args = "()", - description = "Gets the maximum number of sprites the SpriteBatch can hold.", - returns = "(size: number)", - type = "function" - }, - getColor = { - args = "(r: number, g: number, b: number, a: number)", - description = "Gets the color that will be used for the next add and set operations.\n\nIf no color has been set with SpriteBatch:setColor or the current SpriteBatch color has been cleared, this method will return nil.", - returns = "()", - type = "function" - }, - getCount = { - args = "()", - description = "Gets the amount of sprites currently in the SpriteBatch.", - returns = "(count: number)", - type = "function" - }, - getTexture = { - args = "()", - description = "Returns the Image or Canvas used by the SpriteBatch.", - returns = "(texture: Texture)", - type = "function" - }, - set = { - args = "(id: number, x: number, y: number, r: number, sx: number, sy: number, ox: number, oy: number, kx: number, ky: number)", - description = "Changes a sprite in the batch. This requires the identifier returned by add and addq.", - returns = "()", - type = "function" - }, - setBufferSize = { - args = "(size: number)", - description = "Sets the maximum number of sprites the SpriteBatch can hold. Existing sprites in the batch (up to the new maximum) will not be cleared when this function is called.", - returns = "()", - type = "function" - }, - setColor = { - args = "(r: number, g: number, b: number, a: number)", - description = "Sets the color that will be used for the next add and set operations. Calling the function without arguments will clear the color.\n\nThe global color set with love.graphics.setColor will not work on the SpriteBatch if any of the sprites has its own color.", - returns = "()", - type = "function" - }, - setTexture = { - args = "(texture: Texture)", - description = "Replaces the Image or Canvas used for the sprites.", - returns = "()", - type = "function" - } - }, - description = "Using a single image, draw any number of identical copies of the image using a single call to love.graphics.draw. This can be used, for example, to draw repeating copies of a single background image.\n\nA SpriteBatch can be even more useful when the underlying image is a Texture Atlas (a single image file containing many independent images); by adding Quad to the batch, different sub-images from within the atlas can be drawn.", - type = "lib" - }, - SpriteBatchUsage = { - childs = { - dynamic = { - description = "The object's data will change repeatedly during its lifetime.", - type = "value" - }, - static = { - description = "The object will not be modified after initial sprites or vertices are added.", - type = "value" - }, - stream = { - description = "The object data will always change between draws.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - StackType = { - childs = { - all = { - description = "All love.graphics state, including transform state.", - type = "value" - }, - transform = { - description = "The transformation stack (love.graphics.translate, love.graphics.rotate, etc.)", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Text = { - childs = { - addf = { - args = "(textstring: string, wraplimit: number, align: AlignMode, x: number, y: number, angle: number, sx: number, sy: number, ox: number, oy: number, kx: number, ky: number)", - description = "Adds additional formatted / colored text to the Text object at the specified position.", - returns = "(index: number)", - type = "function" - }, - clear = { - args = "()", - description = "Clears the contents of the Text object.", - returns = "()", - type = "function" - }, - getFont = { - args = "()", - description = "Gets the Font used with the Text object.", - returns = "(font: Font)", - type = "function" - }, - getHeight = { - args = "(index: number)", - description = "Gets the height of the text in pixels.", - returns = "(height: number)", - type = "function" - }, - getWidth = { - args = "(index: number)", - description = "Gets the width of the text in pixels.", - returns = "(width: number)", - type = "function" - }, - set = { - args = "(textstring: string)", - description = "Replaces the contents of the Text object with a new unformatted string.", - returns = "()", - type = "function" - }, - setFont = { - args = "(font: Font)", - description = "Replaces the Font used with the text.", - returns = "()", - type = "function" - }, - setf = { - args = "(textstring: string, wraplimit: number, align: AlignMode)", - description = "Replaces the contents of the Text object with a new formatted string.", - returns = "()", - type = "function" - } - }, - description = "Drawable text.", - type = "lib" - }, - TextureFormat = { - childs = { - hdr = { - description = "Only usable in Canvases. The HDR texture format: floating point 16 bits per channel (64 bpp) RGBA.", - type = "value" - }, - normal = { - description = "The default texture format: 8 bits per channel (32 bpp) RGBA.", - type = "value" - }, - srgb = { - description = "The same as normal, but the texture is interpreted as being in the sRGB color space. It will be decoded from sRGB to linear RGB when drawn or sampled from in a shader. For Canvases, this will also convert everything drawn to the Canvas from linear RGB to sRGB.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - WrapMode = { - childs = { - clamp = { - description = "How the image wraps inside a Quad with a larger quad size than image size. This also affects how Meshes with texture coordinates which are outside the range of [0, 1] are drawn, and the color returned by the Texel Shader function when using it to sample from texture coordinates outside of the range of [0, 1].", - type = "value" - }, - clampzero = { - description = "Clamp the texture. Fills the area outside the texture's normal range with transparent black (or opaque black for textures with no alpha channel.)", - type = "value" - }, - mirroredrepeat = { - description = "Repeat the texture, flipping it each time it repeats. May produce better visual results than the repeat mode when the texture doesn't seamlessly tile.", - type = "value" - }, - ["repeat"] = { - description = "Repeat the image. Fills the whole available extent.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - circle = { - args = "(mode: DrawMode, x: number, y: number, radius: number, segments: number)", - description = "Draws a circle.", - returns = "()", - type = "function" - }, - clear = { - args = "(r: number, g: number, b: number, a: number)", - description = "Clears the screen to the background color in LÖVE 0.9.2 and earlier, or to the specified color in 0.10.0 and newer.\n\nThis function is called automatically before love.draw in the default love.run function. See the example in love.run for a typical use of this function.\n\nNote that the scissor area bounds the cleared region.", - returns = "()", - type = "function" - }, - discard = { - args = "(discardcolor: boolean, discardstencil: boolean)", - description = "Discards (trashes) the contents of the screen or active Canvas. This is a performance optimization function with niche use cases.\n\nIf the active Canvas has just been changed and the \"replace\" BlendMode is about to be used to draw something which covers the entire screen, calling love.graphics.discard rather than calling love.graphics.clear or doing nothing may improve performance on mobile devices.\n\nOn some desktop systems this function may do nothing.", - returns = "()", - type = "function" - }, - draw = { - args = "(drawable: Drawable, x: number, y: number, r: number, sx: number, sy: number, ox: number, oy: number, kx: number, ky: number)", - description = "Draws objects on screen. Drawable objects are loaded images, but may be other kinds of Drawable objects, such as a ParticleSystem.\n\nIn addition to simple drawing, this function can rotate and scale the object at the same time, as well as offset the image (for example, to center the image at the chosen coordinates).\n\nlove.graphics.draw anchors from the top left corner by default.\n\nYou can specify a negative value for sx or sy to flip the drawable horizontally or vertically.\n\nThe pivotal point is (x, y) on the screen and (ox, oy) in the internal coordinate system of the drawable object, before rotation and scaling. The object is scaled by (sx, sy), then rotated by r around the pivotal point.\n\nThe origin offset values are most often used to shift the images up and left by half of its height and width, so that (effectively) the specified x and y coordinates are where the center of the image will end up.", - returns = "()", - type = "function" - }, - ellipse = { - args = "(mode: DrawMode, x: number, y: number, radiusx: number, radiusy: number)", - description = "Draws an ellipse.", - returns = "()", - type = "function" - }, - getBackgroundColor = { - args = "()", - description = "Gets the current background color.", - returns = "(r: number, g: number, b: number, a: number)", - type = "function" - }, - getBlendMode = { - args = "()", - description = "Gets the blending mode.", - returns = "(mode: BlendMode)", - type = "function" - }, - getCanvas = { - args = "()", - description = "Gets the current target Canvas.", - returns = "(canvas: Canvas)", - type = "function" - }, - getCanvasFormats = { - args = "()", - description = "Gets the available Canvas formats, and whether each is supported.", - returns = "(formats: table)", - type = "function" - }, - getColor = { - args = "()", - description = "Gets the current color.", - returns = "(r: number, g: number, b: number, a: number)", - type = "function" - }, - getColorMask = { - args = "()", - description = "Gets the active color components used when drawing. Normally all 4 components are active unless love.graphics.setColorMask has been used.\n\nThe color mask determines whether individual components of the colors of drawn objects will affect the color of the screen. They affect love.graphics.clear and Canvas:clear as well.", - returns = "(r: boolean, g: boolean, b: boolean, a: boolean)", - type = "function" - }, - getCompressedImageFormats = { - args = "()", - description = "Gets the available compressed image formats, and whether each is supported.", - returns = "(formats: table)", - type = "function" - }, - getDefaultFilter = { - args = "()", - description = "Returns the default scaling filters used with Images, Canvases, and Fonts.", - returns = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - type = "function" - }, - getDimensions = { - args = "()", - description = "Gets the width and height of the window.", - returns = "(width: number, height: number)", - type = "function" - }, - getFSAA = { - args = "()", - description = "Gets the number of antialiasing samples used when drawing to the Canvas.\n\nThis may be different than the number used as an argument to love.graphics.newCanvas if the system running LÖVE doesn't support that number.", - returns = "(samples: number)", - type = "function" - }, - getFont = { - args = "()", - description = "Gets the current Font object.", - returns = "(font: Font)", - type = "function" - }, - getFullscreenModes = { - args = "()", - description = "Gets a list of supported fullscreen modes.", - returns = "(modes: table)", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the window.", - returns = "(height: number)", - type = "function" - }, - getLineJoin = { - args = "()", - description = "Gets the line join style.", - returns = "(join: LineJoin)", - type = "function" - }, - getLineStyle = { - args = "()", - description = "Gets the line style.", - returns = "(style: LineStyle)", - type = "function" - }, - getLineWidth = { - args = "()", - description = "Gets the current line width.", - returns = "(width: number)", - type = "function" - }, - getPointSize = { - args = "()", - description = "Gets the point size.", - returns = "(size: number)", - type = "function" - }, - getRendererInfo = { - args = "()", - description = "Gets information about the system's video card and drivers.", - returns = "(name: string, version: string, vendor: string, device: string)", - type = "function" - }, - getScissor = { - args = "()", - description = "Gets the current scissor box.", - returns = "(x: number, y: number, width: number, height: number)", - type = "function" - }, - getShader = { - args = "()", - description = "Returns the current Shader. Returns nil if none is set.", - returns = "(shader: Shader)", - type = "function" - }, - getStats = { - args = "()", - description = "Gets performance-related rendering statistics.", - returns = "(drawcalls: number, canvasswitches: number, texturememory: number, images: number, canvases: number, fonts: number)", - type = "function" - }, - getStencilTest = { - args = "()", - description = "Gets whether stencil testing is enabled.\n\nWhen stencil testing is enabled, the geometry of everything that is drawn will be clipped / stencilled out based on whether it intersects with what has been previously drawn to the stencil buffer.\n\nEach Canvas has its own stencil buffer.", - returns = "(enabled: boolean, inverted: boolean)", - type = "function" - }, - getSupported = { - args = "()", - description = "Gets the optional graphics features and whether they're supported on the system.\n\nSome older or low-end systems don't always support all graphics features.", - returns = "(features: table)", - type = "function" - }, - getSystemLimits = { - args = "()", - description = "Gets the system-dependent maximum values for love.graphics features.", - returns = "(limits: table)", - type = "function" - }, - getWidth = { - args = "()", - description = "Gets the width of the window.", - returns = "(width: number)", - type = "function" - }, - intersectScissor = { - args = "(x: number, y: number, width: number, height: number)", - description = "Sets the scissor to the rectangle created by the intersection of the specified rectangle with the existing scissor. If no scissor is active yet, it behaves like love.graphics.setScissor.\n\nThe scissor limits the drawing area to a specified rectangle. This affects all graphics calls, including love.graphics.clear.\n\nThe dimensions of the scissor is unaffected by graphical transformations (translate, scale, ...).", - returns = "()", - type = "function" - }, - isGammaCorrect = { - args = "()", - description = "Gets whether gamma-correct rendering is supported and enabled. It can be enabled by setting t.gammacorrect = true in love.conf.\n\nNot all devices support gamma-correct rendering, in which case it will be automatically disabled and this function will return false. It is supported on desktop systems which have graphics cards that are capable of using OpenGL 3 / DIrectX 10, and iOS devices that can use OpenGL ES 3.", - returns = "(gammacorrect: boolean)", - type = "function" - }, - isWireframe = { - args = "()", - description = "Gets whether wireframe mode is used when drawing.", - returns = "(wireframe: boolean)", - type = "function" - }, - line = { - args = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - description = "Draws lines between points.", - returns = "()", - type = "function" - }, - newCanvas = { - args = "(width: number, height: number, texture_type: TextureFormat, fsaa: number)", - description = "Creates a new Canvas object for offscreen rendering.\n\nAntialiased Canvases have slightly higher system requirements than normal Canvases. Additionally, the supported maximum number of FSAA samples varies depending on the system. Use love.graphics.getSystemLimit to check.\n\nIf the number of FSAA samples specified is greater than the maximum supported by the system, the Canvas will still be created but only using the maximum supported amount (this includes 0.)", - returns = "(canvas: Canvas)", - type = "function" - }, - newFont = { - args = "(filename: string, size: number)", - description = "Creates a new Font.", - returns = "(font: Font)", - type = "function" - }, - newImage = { - args = "(filename: string)", - description = "Creates a new Image from a filepath, FileData, an ImageData, or a CompressedImageData, and optionally generates or specifies mipmaps for the image.", - returns = "(image: Image)", - type = "function" - }, - newImageFont = { - args = "(filename: string, glyphs: string)", - description = "Creates a new Font by loading a specifically formatted image. There can be up to 256 glyphs.\n\nIn versions prior to 0.9.0, LÖVE expects ISO 8859-1 encoding for the glyphs string.", - returns = "(font: Font)", - type = "function" - }, - newMesh = { - args = "(vertices: table, mode: MeshDrawMode, usage: SpriteBatchUsage)", - description = "Creates a new Mesh.\n\nUse Mesh:setTexture if the Mesh should be textured with an Image or Canvas when it's drawn.", - returns = "(mesh: Mesh)", - type = "function" - }, - newParticleSystem = { - args = "(texture: Texture, buffer: number)", - description = "Creates a new ParticleSystem.", - returns = "(system: ParticleSystem)", - type = "function" - }, - newQuad = { - args = "(x: number, y: number, width: number, height: number, sw: number, sh: number)", - description = "Creates a new Quad.\n\nThe purpose of a Quad is to describe the result of the following transformation on any drawable object. The object is first scaled to dimensions sw * sh. The Quad then describes the rectangular area of dimensions width * height whose upper left corner is at position (x, y) inside the scaled object.", - returns = "(quad: Quad)", - type = "function" - }, - newScreenshot = { - args = "()", - description = "Creates a screenshot and returns the image data.", - returns = "(screenshot: ImageData)", - type = "function" - }, - newShader = { - args = "(code: string)", - description = "Creates a new Shader object for hardware-accelerated vertex and pixel effects. A Shader contains either vertex shader code, pixel shader code, or both.\n\nVertex shader code must contain at least one function, named position, which is the function that will produce transformed vertex positions of drawn objects in screen-space.\n\nPixel shader code must contain at least one function, named effect, which is the function that will produce the color which is blended onto the screen for each pixel a drawn object touches.", - returns = "(shader: Shader)", - type = "function" - }, - newSpriteBatch = { - args = "(texture: Texture, size: number, usage: SpriteBatchUsage)", - description = "Creates a new SpriteBatch object.", - returns = "(spriteBatch: SpriteBatch)", - type = "function" - }, - newText = { - args = "(font: Font, textstring: string)", - description = "Creates a new Font.", - returns = "(text: Text)", - type = "function" - }, - newVideo = { - args = "(filename: string, loadaudio: boolean)", - description = "Creates a new drawable Video. Currently only Ogg Theora video files are supported.", - returns = "(video: Video)", - type = "function" - }, - origin = { - args = "()", - description = "Resets the current coordinate transformation.\n\nThis function is always used to reverse any previous calls to love.graphics.rotate, love.graphics.scale, love.graphics.shear or love.graphics.translate. It returns the current transformation state to its defaults.", - returns = "()", - type = "function" - }, - points = { - args = "(x: number, y: number, ...: number)", - description = "Draws one or more points.", - returns = "()", - type = "function" - }, - polygon = { - args = "(mode: DrawMode, ...: number)", - description = "Draw a polygon.\n\nFollowing the mode argument, this function can accept multiple numeric arguments or a single table of numeric arguments. In either case the arguments are interpreted as alternating x and y coordinates of the polygon's vertices.\n\nWhen in fill mode, the polygon must be convex and simple or rendering artifacts may occur.", - returns = "()", - type = "function" - }, - pop = { - args = "()", - description = "Pops the current coordinate transformation from the transformation stack.\n\nThis function is always used to reverse a previous push operation. It returns the current transformation state to what it was before the last preceding push. For an example, see the description of love.graphics.push.", - returns = "()", - type = "function" - }, - present = { - args = "()", - description = "Displays the results of drawing operations on the screen.\n\nThis function is used when writing your own love.run function. It presents all the results of your drawing operations on the screen. See the example in love.run for a typical use of this function.", - returns = "()", - type = "function" - }, - print = { - args = "(text: string, x: number, y: number, r: number, sx: number, sy: number, ox: number, oy: number, kx: number, ky: number)", - description = "Draws text on screen. If no Font is set, one will be created and set (once) if needed.\n\nWhen using translation and scaling functions while drawing text, this function assumes the scale occurs first. If you don't script with this in mind, the text won't be in the right position, or possibly even on screen.\n\nlove.graphics.print stops at the first '\0' (null) character. This can bite you if you are appending keystrokes to form your string, as some of those are multi-byte unicode characters which will likely contain null bytes.", - returns = "()", - type = "function" - }, - printf = { - args = "(text: string, x: number, y: number, limit: number, align: AlignMode, r: number, sx: number, sy: number, ox: number, oy: number, kx: number, ky: number)", - description = "Draws formatted text, with word wrap and alignment.\n\nSee additional notes in love.graphics.print.", - returns = "()", - type = "function" - }, - push = { - args = "(stack: StackType)", - description = "Copies and pushes the current coordinate transformation to the transformation stack.\n\nThis function is always used to prepare for a corresponding pop operation later. It stores the current coordinate transformation state into the transformation stack and keeps it active. Later changes to the transformation can be undone by using the pop operation, which returns the coordinate transform to the state it was in before calling push.", - returns = "()", - type = "function" - }, - rectangle = { - args = "(mode: DrawMode, x: number, y: number, width: number, height: number)", - description = "Draws a rectangle.", - returns = "()", - type = "function" - }, - reset = { - args = "()", - description = "Resets the current graphics settings.\n\nCalling reset makes the current drawing color white, the current background color black, resets any active Canvas or Shader, and removes any scissor settings. It sets the BlendMode to alpha. It also sets both the point and line drawing modes to smooth and their sizes to 1.0.", - returns = "()", - type = "function" - }, - rotate = { - args = "(angle: number)", - description = "Rotates the coordinate system in two dimensions.\n\nCalling this function affects all future drawing operations by rotating the coordinate system around the origin by the given amount of radians. This change lasts until love.draw exits.", - returns = "()", - type = "function" - }, - scale = { - args = "(sx: number, sy: number)", - description = "Scales the coordinate system in two dimensions.\n\nBy default the coordinate system in LÖVE corresponds to the display pixels in horizontal and vertical directions one-to-one, and the x-axis increases towards the right while the y-axis increases downwards. Scaling the coordinate system changes this relation.\n\nAfter scaling by sx and sy, all coordinates are treated as if they were multiplied by sx and sy. Every result of a drawing operation is also correspondingly scaled, so scaling by (2, 2) for example would mean making everything twice as large in both x- and y-directions. Scaling by a negative value flips the coordinate system in the corresponding direction, which also means everything will be drawn flipped or upside down, or both. Scaling by zero is not a useful operation.\n\nScale and translate are not commutative operations, therefore, calling them in different orders will change the outcome.\n\nScaling lasts until love.draw exits.", - returns = "()", - type = "function" - }, - setBackgroundColor = { - args = "(r: number, g: number, b: number, a: number)", - description = "Sets the background color.", - returns = "()", - type = "function" - }, - setBlendMode = { - args = "(mode: BlendMode)", - description = "Sets the blending mode.", - returns = "()", - type = "function" - }, - setCanvas = { - args = "(canvas: Canvas, ...: Canvas)", - description = "Sets the render target to one or more Canvases. All drawing operations until the next love.graphics.setCanvas call will be redirected to the specified canvases and not shown on the screen.\n\nAll canvas arguments must have the same widths and heights and the same texture type. Normally the same thing will be drawn on each canvas, but that can be changed if a pixel shader is used with the \"effects\" function instead of the regular effect.\n\nNot all computers support Canvases, and not all computers which support Canvases will support multiple render targets. Use love.graphics.isSupported to check.\n\nnWhen called without arguments, the render target is reset to the screen.", - returns = "()", - type = "function" - }, - setColor = { - args = "(red: number, green: number, blue: number, alpha: number)", - description = "Sets the color used for drawing.", - returns = "()", - type = "function" - }, - setColorMask = { - args = "(red: boolean, green: boolean, blue: boolean, alpha: boolean)", - description = "Sets the color mask. Enables or disables specific color components when rendering and clearing the screen. For example, if red is set to false, no further changes will be made to the red component of any pixels.\n\nEnables all color components when called without arguments.", - returns = "()", - type = "function" - }, - setDefaultFilter = { - args = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - description = "Sets the default scaling filters used with Images, Canvases, and Fonts.\n\nThis function does not apply retroactively to loaded images.", - returns = "()", - type = "function" - }, - setFont = { - args = "(font: Font)", - description = "Set an already-loaded Font as the current font or create and load a new one from the file and size.\n\nIt's recommended that Font objects are created with love.graphics.newFont in the loading stage and then passed to this function in the drawing stage.", - returns = "()", - type = "function" - }, - setInvertedStencil = { - args = "(stencilFunction: function)", - description = "Defines an inverted stencil for the drawing operations or releases the active one.\n\nIt's the same as love.graphics.setStencil with the mask inverted.\n\nCalling the function without arguments releases the active stencil.", - returns = "()", - type = "function" - }, - setLineJoin = { - args = "(join: LineJoin)", - description = "Sets the line join style.", - returns = "()", - type = "function" - }, - setLineStyle = { - args = "(style: LineStyle)", - description = "Sets the line style.", - returns = "()", - type = "function" - }, - setLineWidth = { - args = "(width: number)", - description = "Sets the line width.", - returns = "()", - type = "function" - }, - setNewFont = { - args = "(size: number)", - description = "Creates and sets a new font.", - returns = "(font: Font)", - type = "function" - }, - setPointSize = { - args = "(size: number)", - description = "Sets the point size.", - returns = "()", - type = "function" - }, - setScissor = { - args = "(x: number, y: number, width: number, height: number)", - description = "Sets or disables scissor.\n\nThe scissor limits the drawing area to a specified rectangle. This affects all graphics calls, including love.graphics.clear.", - returns = "()", - type = "function" - }, - setShader = { - args = "(shader: Shader)", - description = "Sets or resets a Shader as the current pixel effect or vertex shaders. All drawing operations until the next love.graphics.setShader will be drawn using the Shader object specified.\n\nDisables the shaders when called without arguments.", - returns = "()", - type = "function" - }, - setStencilTest = { - args = "(comparemode: CompareMode, comparevalue: number)", - description = "Configures or disables stencil testing.\n\nWhen stencil testing is enabled, the geometry of everything that is drawn afterward will be clipped / stencilled out based on a comparison between the arguments of this function and the stencil value of each pixel that the geometry touches. The stencil values of pixels are affected via love.graphics.stencil.\n\nEach Canvas has its own per-pixel stencil values.", - returns = "()", - type = "function" - }, - setWireframe = { - args = "(enable: boolean)", - description = "Sets whether wireframe lines will be used when drawing.\n\nWireframe mode should only be used for debugging. The lines drawn with it enabled do not behave like regular love.graphics lines: their widths don't scale with the coordinate transformations or with love.graphics.setLineWidth, and they don't use the smooth LineStyle.", - returns = "()", - type = "function" - }, - shear = { - args = "(kx: number, ky: number)", - description = "Shears the coordinate system.", - returns = "()", - type = "function" - }, - stencil = { - args = "(stencilfunction: function, action: StencilAction, value: number, keepvalues: boolean)", - description = "Draws geometry as a stencil.\n\nThe geometry drawn by the supplied function sets invisible stencil values of pixels, instead of setting pixel colors. The stencil values of pixels can act like a mask / stencil - love.graphics.setStencilTest can be used afterward to determine how further rendering is affected by the stencil values in each pixel.\n\nEach Canvas has its own per-pixel stencil values. Stencil values are within the range of [0, 255].", - returns = "()", - type = "function" - }, - translate = { - args = "(dx: number, dy: number)", - description = "Translates the coordinate system in two dimensions.\n\nWhen this function is called with two numbers, dx, and dy, all the following drawing operations take effect as if their x and y coordinates were x+dx and y+dy.\n\nScale and translate are not commutative operations, therefore, calling them in different orders will change the outcome.\n\nThis change lasts until love.graphics.clear is called (which is called automatically before love.draw in the default love.run function), or a love.graphics.pop reverts to a previous coordinate system state.\n\nTranslating using whole numbers will prevent tearing/blurring of images and fonts draw after translating.", - returns = "()", - type = "function" - } - }, - description = "The primary responsibility for the love.graphics module is the drawing of lines, shapes, text, Images and other Drawable objects onto the screen. Its secondary responsibilities include loading external files (including Images and Fonts) into memory, creating specialized objects (such as ParticleSystems or Framebuffers) and managing screen geometry.\n\nLÖVE's coordinate system is rooted in the upper-left corner of the screen, which is at location (0, 0). The x-axis is horizontal: larger values are further to the right. The y-axis is vertical: larger values are further towards the bottom.\n\nIn many cases, you draw images or shapes in terms of their upper-left corner (See the picture above).\n\nMany of the functions are used to manipulate the graphics coordinate system, which is essentially the way coordinates are mapped to the display. You can change the position, scale, and even rotation in this way.", - type = "class" - }, - image = { - childs = { - CompressedImageData = { - childs = { - getFormat = { - args = "()", - description = "Gets the format of the CompressedImageData.", - returns = "(format: CompressedImageFormat)", - type = "function" - }, - getHeight = { - args = "(level: number)", - description = "Gets the height of the CompressedImageData.", - returns = "(height: number)", - type = "function" - }, - getMipmapCount = { - args = "(mipmaps: number)", - description = "Gets the number of mipmap levels in the CompressedImageData. The base mipmap level (original image) is included in the count.", - returns = "()", - type = "function" - }, - getWidth = { - args = "(level: number)", - description = "Gets the width of the CompressedImageData.", - returns = "(width: number)", - type = "function" - } - }, - description = "Represents compressed image data designed to stay compressed in RAM.\n\nCompressedImageData encompasses standard compressed texture formats such as DXT1, DXT5, and BC5 / 3Dc.\n\nYou can't draw CompressedImageData directly to the screen. See Image for that.", - type = "lib" - }, - CompressedImageFormat = { - childs = { - ASTC4x4 = { - description = "The 4x4 pixels per block variant of the ASTC format. RGBA data at 8 bits per pixel.", - type = "value" - }, - ASTC5x4 = { - description = "The 5x4 pixels per block variant of the ASTC format. RGBA data at 6.4 bits per pixel.", - type = "value" - }, - ASTC5x5 = { - description = "The 5x5 pixels per block variant of the ASTC format. RGBA data at 5.12 bits per pixel.", - type = "value" - }, - ASTC6x5 = { - description = "The 6x5 pixels per block variant of the ASTC format. RGBA data at 4.27 bits per pixel.", - type = "value" - }, - ASTC6x6 = { - description = "The 6x6 pixels per block variant of the ASTC format. RGBA data at 3.56 bits per pixel.", - type = "value" - }, - ASTC8x5 = { - description = "The 8x5 pixels per block variant of the ASTC format. RGBA data at 3.2 bits per pixel.", - type = "value" - }, - ASTC8x6 = { - description = "The 8x6 pixels per block variant of the ASTC format. RGBA data at 2.67 bits per pixel.", - type = "value" - }, - ASTC8x8 = { - description = "The 8x8 pixels per block variant of the ASTC format. RGBA data at 2 bits per pixel.", - type = "value" - }, - ASTC10x5 = { - description = "The 10x5 pixels per block variant of the ASTC format. RGBA data at 2.56 bits per pixel.", - type = "value" - }, - ASTC10x6 = { - description = "The 10x6 pixels per block variant of the ASTC format. RGBA data at 2.13 bits per pixel.", - type = "value" - }, - ASTC10x8 = { - description = "The 10x8 pixels per block variant of the ASTC format. RGBA data at 1.6 bits per pixel.", - type = "value" - }, - ASTC10x10 = { - description = "The 10x10 pixels per block variant of the ASTC format. RGBA data at 1.28 bits per pixel.", - type = "value" - }, - ASTC12x10 = { - description = "The 12x10 pixels per block variant of the ASTC format. RGBA data at 1.07 bits per pixel.", - type = "value" - }, - ASTC12x12 = { - description = "The 12x12 pixels per block variant of the ASTC format. RGBA data at 0.89 bits per pixel.", - type = "value" - }, - BC4 = { - description = "The BC4 format (also known as 3Dc+ or ATI1.) Stores just the red channel, at 4 bits per pixel.", - type = "value" - }, - BC4s = { - description = "The signed variant of the BC4 format. Same as above but the pixel values in the texture are in the range of [-1, 1] instead of [0, 1] in shaders.", - type = "value" - }, - BC5 = { - description = "The BC5 format (also known as 3Dc or ATI2.) Stores red and green channels at 8 bits per pixel.", - type = "value" - }, - BC5s = { - description = "The signed variant of the BC5 format.", - type = "value" - }, - BC6h = { - description = "The BC6H format. Stores half-precision floating-point RGB data in the range of [0, 65504] at 8 bits per pixel. Suitable for HDR images on desktop systems.", - type = "value" - }, - BC6hs = { - description = "The signed variant of the BC6H format. Stores RGB data in the range of [-65504, +65504].", - type = "value" - }, - BC7 = { - description = "The BC7 format (also known as BPTC.) Stores RGB or RGBA data at 8 bits per pixel.", - type = "value" - }, - DXT1 = { - description = "The DXT1 format. RGB data at 4 bits per pixel (compared to 32 bits for ImageData and regular Images.) Suitable for fully opaque images. Suitable for fully opaque images on desktop systems.", - type = "value" - }, - DXT3 = { - description = "The DXT3 format. RGBA data at 8 bits per pixel. Smooth variations in opacity do not mix well with this format.", - type = "value" - }, - DXT5 = { - description = "The DXT5 format. RGBA data at 8 bits per pixel. Recommended for images with varying opacity on desktop systems.", - type = "value" - }, - EACr = { - description = "The single-channel variant of the EAC format. Stores just the red channel, at 4 bits per pixel.", - type = "value" - }, - EACrg = { - description = "The two-channel variant of the EAC format. Stores red and green channels at 8 bits per pixel.", - type = "value" - }, - EACrgs = { - description = "The signed two-channel variant of the EAC format.", - type = "value" - }, - EACrs = { - description = "The signed single-channel variant of the EAC format. Same as above but pixel values in the texture are in the range of [-1, 1] instead of [0, 1] in shaders.", - type = "value" - }, - ETC1 = { - description = "The ETC1 format. RGB data at 4 bits per pixel. Suitable for fully opaque images on older Android devices.", - type = "value" - }, - ETC2rgb = { - description = "The RGB variant of the ETC2 format. RGB data at 4 bits per pixel. Suitable for fully opaque images on newer mobile devices.", - type = "value" - }, - ETC2rgba = { - description = "The RGBA variant of the ETC2 format. RGBA data at 8 bits per pixel. Recommended for images with varying opacity on newer mobile devices.", - type = "value" - }, - ETC2rgba1 = { - description = "The RGBA variant of the ETC2 format where pixels are either fully transparent or fully opaque. RGBA data at 4 bits per pixel.", - type = "value" - }, - PVR1rgb2 = { - description = "The 2 bit per pixel RGB variant of the PVRTC1 format. Stores RGB data at 2 bits per pixel. Textures compressed with PVRTC1 formats must be square and power-of-two sized.", - type = "value" - }, - PVR1rgb4 = { - description = "The 4 bit per pixel RGB variant of the PVRTC1 format. Stores RGB data at 4 bits per pixel.", - type = "value" - }, - PVR1rgba2 = { - description = "The 2 bit per pixel RGBA variant of the PVRTC1 format.", - type = "value" - }, - PVR1rgba4 = { - description = "The 4 bit per pixel RGBA variant of the PVRTC1 format.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - ImageData = { - childs = { - getDimensions = { - args = "()", - description = "Gets the width and height of the ImageData.", - returns = "(width: number, height: number)", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the ImageData.", - returns = "(height: number)", - type = "function" - }, - getPixel = { - args = "(x: number, y: number)", - description = "Gets the pixel at the specified position.\n\nValid x and y values start at 0 and go up to image width and height minus 1.", - returns = "(r: number, g: number, b: number, a: number)", - type = "function" - }, - getWidth = { - args = "()", - description = "Gets the width of the ImageData.", - returns = "(width: number)", - type = "function" - }, - mapPixel = { - args = "(pixelFunction: function)", - description = "Transform an image by applying a function to every pixel.\n\nThis function is a higher order function. It takes another function as a parameter, and calls it once for each pixel in the ImageData.\n\nThe function parameter is called with six parameters for each pixel in turn. The parameters are numbers that represent the x and y coordinates of the pixel and its red, green, blue and alpha values. The function parameter can return up to four number values, which become the new r, g, b and a values of the pixel. If the function returns fewer values, the remaining components are set to 0.", - returns = "()", - type = "function" - }, - paste = { - args = "(source: ImageData, dx: number, dy: number, sx: number, sy: number, sw: number, sh: number)", - description = "Paste into ImageData from another source ImageData.", - returns = "()", - type = "function" - }, - setPixel = { - args = "(x: number, y: number, r: number, g: number, b: number, a: number)", - description = "Sets the color of a pixel.\n\nValid x and y values start at 0 and go up to image width and height minus 1.", - returns = "()", - type = "function" - } - }, - description = "Raw (decoded) image data.\n\nYou can't draw ImageData directly to screen. See Image for that.", - type = "lib" - }, - ImageFormat = { - childs = { - png = { - description = "PNG image format.", - type = "value" - }, - tga = { - description = "Targa image format.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - newCompressedData = { - args = "(filename: string)", - description = "Create a new CompressedImageData object from a compressed image file. LÖVE supports several compressed texture formats, enumerated in the CompressedImageFormat page.", - returns = "(compressedImageData: CompressedImageData)", - type = "function" - }, - newImageData = { - args = "(width: number, height: number)", - description = "Create a new ImageData object.", - returns = "(imageData: ImageData)", - type = "function" - } - }, - description = "Provides an interface to decode encoded image data.", - type = "class" - }, - joystick = { - childs = { - GamepadAxis = { - childs = { - leftx = { - description = "The x-axis of the left thumbstick.", - type = "value" - }, - lefty = { - description = "The y-axis of the left thumbstick.", - type = "value" - }, - rightx = { - description = "The x-axis of the right thumbstick.", - type = "value" - }, - righty = { - description = "The y-axis of the right thumbstick.", - type = "value" - }, - triggerleft = { - description = "Left analog trigger.", - type = "value" - }, - triggerright = { - description = "Right analog trigger.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - GamepadButton = { - childs = { - a = { - description = "Bottom face button (A).", - type = "value" - }, - b = { - description = "Right face button (B).", - type = "value" - }, - back = { - description = "Back button.", - type = "value" - }, - dpdown = { - description = "D-pad down.", - type = "value" - }, - dpleft = { - description = "D-pad left.", - type = "value" - }, - dpright = { - description = "D-pad right.", - type = "value" - }, - dpup = { - description = "D-pad up.", - type = "value" - }, - guide = { - description = "Guide button.", - type = "value" - }, - leftshoulder = { - description = "Left bumper.", - type = "value" - }, - leftstick = { - description = "Left stick click button.", - type = "value" - }, - rightshoulder = { - description = "Right bumper.", - type = "value" - }, - rightstick = { - description = "Right stick click button.", - type = "value" - }, - start = { - description = "Start button.", - type = "value" - }, - x = { - description = "Left face button (X).", - type = "value" - }, - y = { - description = "Top face button (Y).", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - Joystick = { - childs = { - getAxis = { - args = "(axis: number)", - description = "Gets the direction of an axis.", - returns = "(direction: number)", - type = "function" - }, - getAxisCount = { - args = "()", - description = "Gets the number of axes on the joystick.", - returns = "(axes: number)", - type = "function" - }, - getButtonCount = { - args = "()", - description = "Gets the number of buttons on the joystick.", - returns = "(buttons: number)", - type = "function" - }, - getGUID = { - args = "()", - description = "Gets a stable GUID unique to the type of the physical joystick which does not change over time. For example, all Sony Dualshock 3 controllers in OS X have the same GUID. The value is platform-dependent.", - returns = "(guid: string)", - type = "function" - }, - getGamepadAxis = { - args = "(axis: GamepadAxis)", - description = "Gets the direction of a virtual gamepad axis. If the Joystick isn't recognized as a gamepad or isn't connected, this function will always return 0.", - returns = "(direction: number)", - type = "function" - }, - getGamepadMapping = { - args = "(axis: GamepadAxis)", - description = "Gets the button, axis or hat that a virtual gamepad input is bound to.", - returns = "(inputtype: JoystickInputType, inputindex: number, hatdirection: JoystickHat)", - type = "function" - }, - getHat = { - args = "(hat: number)", - description = "Gets the direction of a hat.", - returns = "(direction: JoystickHat)", - type = "function" - }, - getHatCount = { - args = "()", - description = "Gets the number of hats on the joystick.", - returns = "(hats: number)", - type = "function" - }, - getID = { - args = "()", - description = "Gets the joystick's unique identifier. The identifier will remain the same for the life of the game, even when the Joystick is disconnected and reconnected, but it will change when the game is re-launched.", - returns = "(id: number, instanceid: number)", - type = "function" - }, - getName = { - args = "()", - description = "Gets the name of the joystick.", - returns = "(name: string)", - type = "function" - }, - getVibration = { - args = "()", - description = "Gets the current vibration motor strengths on a Joystick with rumble support.", - returns = "(left: number, right: number)", - type = "function" - }, - isConnected = { - args = "()", - description = "Gets whether the Joystick is connected.", - returns = "(connected: boolean)", - type = "function" - }, - isDown = { - args = "(...: number)", - description = "Checks if a button on the Joystick is pressed.", - returns = "(anyDown: boolean)", - type = "function" - }, - isGamepad = { - args = "()", - description = "Gets whether the Joystick is recognized as a gamepad. If this is the case, the Joystick's buttons and axes can be used in a standardized manner across different operating systems and joystick models via Joystick:getGamepadAxis and related functions.\n\nLÖVE automatically recognizes most popular controllers with a similar layout to the Xbox 360 controller as gamepads, but you can add more with love.joystick.setGamepadMapping.", - returns = "(isgamepad: boolean)", - type = "function" - }, - isGamepadDown = { - args = "(...: GamepadButton)", - description = "Checks if a virtual gamepad button on the Joystick is pressed. If the Joystick is not recognized as a Gamepad or isn't connected, then this function will always return false.", - returns = "(anyDown: boolean)", - type = "function" - }, - isVibrationSupported = { - args = "()", - description = "Gets whether the Joystick supports vibration.", - returns = "(supported: boolean)", - type = "function" - }, - setVibration = { - args = "(left: number, right: number)", - description = "Sets the vibration motor speeds on a Joystick with rumble support.", - returns = "(success: boolean)", - type = "function" - } - }, - description = "Represents a physical joystick.", - type = "lib" - }, - JoystickHat = { - childs = { - c = { - description = "Centered", - type = "value" - }, - d = { - description = "Down", - type = "value" - }, - l = { - description = "Left", - type = "value" - }, - ld = { - description = "Left+Down", - type = "value" - }, - lu = { - description = "Left+Up", - type = "value" - }, - r = { - description = "Right", - type = "value" - }, - rd = { - description = "Right+Down", - type = "value" - }, - ru = { - description = "Right+Up", - type = "value" - }, - u = { - description = "Up", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - JoystickInputType = { - childs = { - axis = { - description = "Analog axis.", - type = "value" - }, - button = { - description = "Button.", - type = "value" - }, - hat = { - description = "8-direction hat value.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - getJoysticks = { - args = "()", - description = "Gets a list of connected Joysticks.", - returns = "(joysticks: table)", - type = "function" - }, - loadGamepadMappings = { - args = "(filename: string)", - description = "Loads a gamepad mappings string or file created with love.joystick.saveGamepadMappings.", - returns = "()", - type = "function" - }, - saveGamepadMappings = { - args = "(filename: string)", - description = "Saves the virtual gamepad mappings of all Joysticks that are recognized as gamepads and have either been recently used or their gamepad bindings have been modified.", - returns = "(mappings: string)", - type = "function" - }, - setGamepadMapping = { - args = "(guid: string, button: GamepadButton, inputtype: JoystickInputType, inputindex: number, hatdirection: JoystickHat)", - description = "Binds a virtual gamepad input to a button, axis or hat for all Joysticks of a certain type. For example, if this function is used with a GUID returned by a Dualshock 3 controller in OS X, the binding will affect Joystick:getGamepadAxis and Joystick:isGamepadDown for all Dualshock 3 controllers used with the game when run in OS X.\n\nLÖVE includes built-in gamepad bindings for many common controllers. This function lets you change the bindings or add new ones for types of Joysticks which aren't recognized as gamepads by default.\n\nThe virtual gamepad buttons and axes are designed around the Xbox 360 controller layout.", - returns = "(success: boolean)", - type = "function" - } - }, - description = "Provides an interface to the user's joystick.", - type = "class" - }, - joystickadded = { - args = "(joystick: Joystick)", - description = "Called when a Joystick is connected.\n\nThis callback is also triggered after love.load for every Joystick which was already connected when the game started up.", - returns = "()", - type = "function" - }, - joystickaxis = { - args = "(joystick: Joystick, axis: number, value: number)", - description = "Called when a joystick axis moves.", - returns = "()", - type = "function" - }, - joystickhat = { - args = "(joystick: Joystick, hat: number, direction: JoystickHat)", - description = "Called when a joystick hat direction changes.", - returns = "()", - type = "function" - }, - joystickpressed = { - args = "(joystick: number, button: number)", - description = "Called when a joystick button is pressed.", - returns = "()", - type = "function" - }, - joystickreleased = { - args = "(joystick: number, button: number)", - description = "Called when a joystick button is released.", - returns = "()", - type = "function" - }, - joystickremoved = { - args = "(joystick: Joystick)", - description = "Called when a Joystick is disconnected.", - returns = "()", - type = "function" - }, - keyboard = { - childs = { - KeyConstant = { - childs = { - ["!"] = { - description = "Exclamation mark key", - type = "value" - }, - ["\""] = { - description = "Double quote key", - type = "value" - }, - ["#"] = { - description = "Hash key", - type = "value" - }, - ["$"] = { - description = "Dollar key", - type = "value" - }, - ["&"] = { - description = "Ampersand key", - type = "value" - }, - ["'"] = { - description = "Single quote key", - type = "value" - }, - ["("] = { - description = "Left parenthesis key", - type = "value" - }, - [")"] = { - description = "Right parenthesis key", - type = "value" - }, - ["*"] = { - description = "Asterisk key", - type = "value" - }, - ["+"] = { - description = "Plus key", - type = "value" - }, - [","] = { - description = "Comma key", - type = "value" - }, - ["-"] = { - description = "Hyphen-minus key", - type = "value" - }, - ["."] = { - description = "Full stop key", - type = "value" - }, - ["/"] = { - description = "Slash key", - type = "value" - }, - ["0"] = { - description = "The zero key", - type = "value" - }, - ["1"] = { - description = "The one key", - type = "value" - }, - ["2"] = { - description = "The two key", - type = "value" - }, - ["3"] = { - description = "The three key", - type = "value" - }, - ["4"] = { - description = "The four key", - type = "value" - }, - ["5"] = { - description = "The five key", - type = "value" - }, - ["6"] = { - description = "The six key", - type = "value" - }, - ["7"] = { - description = "The seven key", - type = "value" - }, - ["8"] = { - description = "The eight key", - type = "value" - }, - ["9"] = { - description = "The nine key", - type = "value" - }, - [":"] = { - description = "Colon key", - type = "value" - }, - [";"] = { - description = "Semicolon key", - type = "value" - }, - ["<"] = { - description = "Less-than key", - type = "value" - }, - ["="] = { - description = "Equal key", - type = "value" - }, - [">"] = { - description = "Greater-than key", - type = "value" - }, - ["?"] = { - description = "Question mark key", - type = "value" - }, - ["@"] = { - description = "At sign key", - type = "value" - }, - ["["] = { - description = "Left square bracket key", - type = "value" - }, - ["\\"] = { - description = "Backslash key", - type = "value" - }, - ["]"] = { - description = "Right square bracket key", - type = "value" - }, - ["^"] = { - description = "Caret key", - type = "value" - }, - _ = { - description = "Underscore key", - type = "value" - }, - ["`"] = { - description = "Grave accent key", - notes = "Also known as the \"Back tick\" key", - type = "value" - }, - a = { - description = "The A key", - type = "value" - }, - appback = { - description = "Application back key", - type = "value" - }, - appbookmarks = { - description = "Application bookmarks key", - type = "value" - }, - appforward = { - description = "Application forward key", - type = "value" - }, - apphome = { - description = "Application home key", - type = "value" - }, - apprefresh = { - description = "Application refresh key", - type = "value" - }, - appsearch = { - description = "Application search key", - type = "value" - }, - b = { - description = "The B key", - type = "value" - }, - backspace = { - description = "Backspace key", - type = "value" - }, - ["break"] = { - description = "Break key", - type = "value" - }, - c = { - description = "The C key", - type = "value" - }, - calculator = { - description = "Calculator key", - type = "value" - }, - capslock = { - description = "Caps-lock key", - notes = "Caps-on is a key press. Caps-off is a key release.", - type = "value" - }, - clear = { - description = "Clear key", - type = "value" - }, - compose = { - description = "Compose key", - type = "value" - }, - d = { - description = "The D key", - type = "value" - }, - delete = { - description = "Delete key", - type = "value" - }, - down = { - description = "Down cursor key", - type = "value" - }, - e = { - description = "The E key", - type = "value" - }, - ["end"] = { - description = "End key", - type = "value" - }, - escape = { - description = "Escape key", - type = "value" - }, - euro = { - description = "Euro (€) key", - type = "value" - }, - f = { - description = "The F key", - type = "value" - }, - f1 = { - description = "The 1st function key", - type = "value" - }, - f2 = { - description = "The 2nd function key", - type = "value" - }, - f3 = { - description = "The 3rd function key", - type = "value" - }, - f4 = { - description = "The 4th function key", - type = "value" - }, - f5 = { - description = "The 5th function key", - type = "value" - }, - f6 = { - description = "The 6th function key", - type = "value" - }, - f7 = { - description = "The 7th function key", - type = "value" - }, - f8 = { - description = "The 8th function key", - type = "value" - }, - f9 = { - description = "The 9th function key", - type = "value" - }, - f10 = { - description = "The 10th function key", - type = "value" - }, - f11 = { - description = "The 11th function key", - type = "value" - }, - f12 = { - description = "The 12th function key", - type = "value" - }, - f13 = { - description = "The 13th function key", - type = "value" - }, - f14 = { - description = "The 14th function key", - type = "value" - }, - f15 = { - description = "The 15th function key", - type = "value" - }, - g = { - description = "The G key", - type = "value" - }, - h = { - description = "The H key", - type = "value" - }, - help = { - description = "Help key", - type = "value" - }, - home = { - description = "Home key", - type = "value" - }, - i = { - description = "The I key", - type = "value" - }, - insert = { - description = "Insert key", - type = "value" - }, - j = { - description = "The J key", - type = "value" - }, - k = { - description = "The K key", - type = "value" - }, - ["kp*"] = { - description = "The numpad multiplication key", - type = "value" - }, - ["kp+"] = { - description = "The numpad addition key", - type = "value" - }, - ["kp-"] = { - description = "The numpad substraction key", - type = "value" - }, - ["kp."] = { - description = "The numpad decimal point key", - type = "value" - }, - ["kp/"] = { - description = "The numpad division key", - type = "value" - }, - kp0 = { - description = "The numpad zero key", - type = "value" - }, - kp1 = { - description = "The numpad one key", - type = "value" - }, - kp2 = { - description = "The numpad two key", - type = "value" - }, - kp3 = { - description = "The numpad three key", - type = "value" - }, - kp4 = { - description = "The numpad four key", - type = "value" - }, - kp5 = { - description = "The numpad five key", - type = "value" - }, - kp6 = { - description = "The numpad six key", - type = "value" - }, - kp7 = { - description = "The numpad seven key", - type = "value" - }, - kp8 = { - description = "The numpad eight key", - type = "value" - }, - kp9 = { - description = "The numpad nine key", - type = "value" - }, - ["kp="] = { - description = "The numpad equals key", - type = "value" - }, - kpenter = { - description = "The numpad enter key", - type = "value" - }, - l = { - description = "The L key", - type = "value" - }, - lalt = { - description = "Left alt key", - type = "value" - }, - lctrl = { - description = "Left control key", - type = "value" - }, - left = { - description = "Left cursor key", - type = "value" - }, - lmeta = { - description = "Left meta key", - type = "value" - }, - lshift = { - description = "Left shift key", - type = "value" - }, - lsuper = { - description = "Left super key", - type = "value" - }, - m = { - description = "The M key", - type = "value" - }, - mail = { - description = "Mail key", - type = "value" - }, - menu = { - description = "Menu key", - type = "value" - }, - mode = { - description = "Mode key", - type = "value" - }, - n = { - description = "The N key", - type = "value" - }, - numlock = { - description = "Num-lock key", - type = "value" - }, - o = { - description = "The O key", - type = "value" - }, - p = { - description = "The P key", - type = "value" - }, - pagedown = { - description = "Page down key", - type = "value" - }, - pageup = { - description = "Page up key", - type = "value" - }, - pause = { - description = "Pause key", - type = "value" - }, - power = { - description = "Power key", - type = "value" - }, - print = { - description = "Print key", - type = "value" - }, - q = { - description = "The Q key", - type = "value" - }, - r = { - description = "The R key", - type = "value" - }, - ralt = { - description = "Right alt key", - type = "value" - }, - rctrl = { - description = "Right control key", - type = "value" - }, - ["return"] = { - description = "Return key", - notes = "Also known as the Enter key", - type = "value" - }, - right = { - description = "Right cursor key", - type = "value" - }, - rmeta = { - description = "Right meta key", - type = "value" - }, - rshift = { - description = "Right shift key", - type = "value" - }, - rsuper = { - description = "Right super key", - type = "value" - }, - s = { - description = "The S key", - type = "value" - }, - scrollock = { - description = "Scroll-lock key", - type = "value" - }, - space = { - description = "Space key", - notes = "In version 0.9.2 and earlier this is represented by the actual space character", - type = "value" - }, - sysreq = { - description = "System request key", - type = "value" - }, - t = { - description = "The T key", - type = "value" - }, - tab = { - description = "Tab key", - type = "value" - }, - u = { - description = "The U key", - type = "value" - }, - undo = { - description = "Undo key", - type = "value" - }, - up = { - description = "Up cursor key", - type = "value" - }, - v = { - description = "The V key", - type = "value" - }, - w = { - description = "The W key", - type = "value" - }, - www = { - description = "WWW key", - type = "value" - }, - x = { - description = "The X key", - type = "value" - }, - y = { - description = "The Y key", - type = "value" - }, - z = { - description = "The Z key", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - getScancodeFromKey = { - args = "(key: KeyConstant)", - description = "Gets the hardware scancode corresponding to the given key.\n\nUnlike key constants, Scancodes are keyboard layout-independent. For example the scancode \"w\" will be generated if the key in the same place as the \"w\" key on an American keyboard is pressed, no matter what the key is labelled or what the user's operating system settings are.\n\nScancodes are useful for creating default controls that have the same physical locations on on all systems.", - returns = "(scancode: Scancode)", - type = "function" - }, - hasKeyRepeat = { - args = "()", - description = "Gets whether key repeat is enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - hasTextInput = { - args = "()", - description = "Gets whether text input events are enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - isDown = { - args = "(key: KeyConstant)", - description = "Checks whether a certain key is down. Not to be confused with love.keypressed or love.keyreleased.", - returns = "(down: boolean)", - type = "function" - }, - isScancodeDown = { - args = "(scancode: Scancode, ...: Scancode)", - description = "Checks whether the specified Scancodes are pressed. Not to be confused with love.keypressed or love.keyreleased.\n\nUnlike regular KeyConstants, Scancodes are keyboard layout-independent. The scancode \"w\" is used if the key in the same place as the \"w\" key on an American keyboard is pressed, no matter what the key is labelled or what the user's operating system settings are.", - returns = "(down: boolean)", - type = "function" - }, - setKeyRepeat = { - args = "(enable: boolean)", - description = "Enables or disables key repeat. It is disabled by default.\n\nThe interval between repeats depends on the user's system settings.", - returns = "()", - type = "function" - }, - setTextInput = { - args = "(enable: boolean)", - description = "Enables or disables text input events. It is enabled by default on Windows, Mac, and Linux, and disabled by default on iOS and Android.", - returns = "()", - type = "function" - } - }, - description = "Provides an interface to the user's keyboard.", - type = "lib" - }, - keypressed = { - args = "(key: KeyConstant, scancode: Scancode, isrepeat: boolean)", - description = "Callback function triggered when a key is pressed.", - returns = "()", - type = "function" - }, - keyreleased = { - args = "(key: KeyConstant)", - description = "Callback function triggered when a keyboard key is released.", - returns = "()", - type = "function" - }, - load = { - args = "(arg: table)", - description = "This function is called exactly once at the beginning of the game.", - returns = "()", - type = "function" - }, - lowmemory = { - args = "()", - description = "Callback function triggered when the system is running out of memory on mobile devices.\n\n Mobile operating systems may forcefully kill the game if it uses too much memory, so any non-critical resource should be removed if possible (by setting all variables referencing the resources to nil, and calling collectgarbage()), when this event is triggered. Sounds and images in particular tend to use the most memory.", - returns = "()", - type = "function" - }, - math = { - childs = { - BezierCurve = { - childs = { - getControlPoint = { - args = "(i: number)", - description = "Get coordinates of the i-th control point. Indices start with 1.", - returns = "(x: number, y: number)", - type = "function" - }, - getControlPointCount = { - args = "()", - description = "Get the number of control points in the Bézier curve.", - returns = "(count: number)", - type = "function" - }, - getDegree = { - args = "()", - description = "Get degree of the Bézier curve. The degree is equal to number-of-control-points - 1.", - returns = "(degree: number)", - type = "function" - }, - getDerivative = { - args = "()", - description = "Get the derivative of the Bézier curve.\n\nThis function can be used to rotate sprites moving along a curve in the direction of the movement and compute the direction perpendicular to the curve at some parameter t.", - returns = "(derivative: BezierCurve)", - type = "function" - }, - getSegment = { - args = "(startpoint: number, endpoint: number)", - description = "Gets a BezierCurve that corresponds to the specified segment of this BezierCurve.", - returns = "(curve: BezierCurve)", - type = "function" - }, - insertControlPoint = { - args = "(x: number, y: number, i: number)", - description = "Insert control point after the i-th control point. Indices start with 1. Negative indices wrap around: -1 is the last control point, -2 the one before the last, etc.", - returns = "()", - type = "function" - }, - removeControlPoint = { - args = "(index: number)", - description = "Removes the specified control point.", - returns = "()", - type = "function" - }, - render = { - args = "(depth: number)", - description = "Get a list of coordinates to be used with love.graphics.line.\n\nThis function samples the Bézier curve using recursive subdivision. You can control the recursion depth using the depth parameter.\n\nIf you are just interested to know the position on the curve given a parameter, use BezierCurve:evalulate.", - returns = "(coordinates: table)", - type = "function" - }, - renderSegment = { - args = "(startpoint: number, endpoint: number, depth: number)", - description = "Get a list of coordinates on a specific part of the curve, to be used with love.graphics.line.\n\nThis function samples the Bézier curve using recursive subdivision. You can control the recursion depth using the depth parameter.\n\nIf you are just need to know the position on the curve given a parameter, use BezierCurve:evaluate.", - returns = "(coordinates: table)", - type = "function" - }, - rotate = { - args = "(angle: number, ox: number, oy: number)", - description = "Rotate the Bézier curve by an angle.", - returns = "()", - type = "function" - }, - scale = { - args = "(s: number, ox: number, oy: number)", - description = "Scale the Bézier curve by a factor.", - returns = "()", - type = "function" - }, - setControlPoint = { - args = "(i: number, ox: number, oy: number)", - description = "Set coordinates of the i-th control point. Indices start with 1.", - returns = "()", - type = "function" - }, - translate = { - args = "(dx: number, dy: number)", - description = "Move the Bézier curve by an offset.", - returns = "()", - type = "function" - } - }, - description = "A Bézier curve object that can evaluate and render Bézier curves of arbitrary degree.", - type = "lib" - }, - CompressedData = { - childs = { - getFormat = { - args = "()", - description = "Gets the compression format of the CompressedData.", - returns = "(format: CompressedDataFormat)", - type = "function" - } - }, - description = "Represents byte data compressed using a specific algorithm.\n\nlove.math.decompress can be used to de-compress the data.", - type = "lib" - }, - CompressedDataFormat = { - childs = { - gzip = { - description = "The gzip format is DEFLATE-compressed data with a slightly larger header than zlib. Since it uses DEFLATE it has the same compression characteristics as the zlib format.", - type = "value" - }, - lz4 = { - description = "The LZ4 compression format. Compresses and decompresses very quickly, but the compression ratio is not the best. LZ4-HC is used when compression level 9 is specified.", - type = "value" - }, - zlib = { - description = "The zlib format is DEFLATE-compressed data with a small bit of header data. Compresses relatively slowly and decompresses moderately quickly, and has a decent compression ratio.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - RandomGenerator = { - childs = { - getState = { - args = "()", - description = "Gets the current state of the random number generator. This returns an opaque implementation-dependent string which is only useful for later use with RandomGenerator:setState.\n\nThis is different from RandomGenerator:getSeed in that getState gets the RandomGenerator's current state, whereas getSeed gets the previously set seed number.\n\nThe value of the state string does not depend on the current operating system.", - returns = "(state: string)", - type = "function" - }, - random = { - args = "(max: number)", - description = "Generates a pseudo-random number in a platform independent manner.", - returns = "(number: number)", - type = "function" - }, - randomNormal = { - args = "(stddev: number, mean: number)", - description = "Get a normally distributed pseudo random number.", - returns = "(number: number)", - type = "function" - }, - setSeed = { - args = "(seed: number)", - description = "Sets the seed of the random number generator using the specified integer number.", - returns = "()", - type = "function" - }, - setState = { - args = "(state: string)", - description = "Sets the current state of the random number generator. The value used as an argument for this function is an opaque implementation-dependent string and should only originate from a previous call to RandomGenerator:getState.\n\nThis is different from RandomGenerator:setSeed in that setState directly sets the RandomGenerator's current implementation-dependent state, whereas setSeed gives it a new seed value.\n\nThe effect of the state string does not depend on the current operating system.", - returns = "()", - type = "function" - } - }, - description = "A random number generation object which has its own random state.", - type = "lib" - }, - decompress = { - args = "(compressedData: CompressedData)", - description = "Decompresses a CompressedData or previously compressed string or Data object.", - returns = "(rawstring: string)", - type = "function" - }, - gammaToLinear = { - args = "(r: number, g: number, b: number)", - description = "Converts a color from gamma-space (sRGB) to linear-space (RGB). This is useful when doing gamma-correct rendering using colors created based on what they look like on-screen.\n\nGamma-space sRGB has more precision in the lower end than linear RGB. Using this function to convert from sRGB to RGB can result in non-integer color values, which get truncated to integers and lose precision when used with other functions such as love.graphics.setColor.", - returns = "(lr: number, lg: number, lb: number)", - type = "function" - }, - getRandomSeed = { - args = "()", - description = "Gets the seed of the random number generator.\n\nThe state is split into two numbers due to Lua's use of doubles for all number values - doubles can't accurately represent integer values above 2^53.", - returns = "(low: number, high: number)", - type = "function" - }, - getRandomState = { - args = "()", - description = "Gets the current state of the random number generator. This returns an opaque implementation-dependent string which is only useful for later use with RandomGenerator:setState.\n\nThis is different from RandomGenerator:getSeed in that getState gets the RandomGenerator's current state, whereas getSeed gets the previously set seed number.\n\nThe value of the state string does not depend on the current operating system.", - returns = "(state: string)", - type = "function" - }, - isConvex = { - args = "(vertices: table)", - description = "Checks whether a polygon is convex.\n\nPolygonShapes in love.physics, some forms of Mesh, and polygons drawn with love.graphics.polygon must be simple convex polygons.", - returns = "(convex: boolean)", - type = "function" - }, - linearToGamma = { - args = "(lr: number, lg: number, lb: number)", - description = "Converts a color from linear-space (RGB) to gamma-space (sRGB). This is useful when storing linear RGB color values in an image, because the linear RGB color space has less precision than sRGB for dark colors, which can result in noticeable color banding when drawing.\n\nIn general, colors chosen based on what they look like on-screen are already in gamma-space and should not be double-converted. Colors calculated using math are often in the linear RGB space.", - returns = "(cr: number, cg: number, cb: number)", - type = "function" - }, - newBezierCurve = { - args = "(vertices: table)", - description = "Creates a new BezierCurve object.\n\nThe number of vertices in the control polygon determines the degree of the curve, e.g. three vertices define a quadratic (degree 2) Bézier curve, four vertices define a cubic (degree 3) Bézier curve, etc.", - returns = "(curve: BezierCurve)", - type = "function" - }, - newRandomGenerator = { - args = "(low: number, high: number)", - description = "Creates a new RandomGenerator object which is completely independent of other RandomGenerator objects and random functions.", - returns = "(rng: RandomGenerator)", - type = "function" - }, - noise = { - args = "(x: number)", - description = "Generates a Simplex or Perlin noise value in 1-4 dimensions.\n\nSimplex noise is closely related to Perlin noise. It is widely used for procedural content generation.\n\nThere are many webpages which discuss Perlin and Simplex noise in detail.", - returns = "(value: number)", - type = "function" - }, - random = { - args = "(max: number)", - description = "Generates a pseudo-random number in a platform independent manner.", - returns = "(number: number)", - type = "function" - }, - randomNormal = { - args = "(stddev: number, mean: number)", - description = "Get a normally distributed pseudo random number.", - returns = "(number: number)", - type = "function" - }, - setRandomSeed = { - args = "(seed: number)", - description = "Sets the seed of the random number generator using the specified integer number.", - returns = "()", - type = "function" - }, - setRandomState = { - args = "(state: string)", - description = "Gets the current state of the random number generator. This returns an opaque implementation-dependent string which is only useful for later use with RandomGenerator:setState.\n\nThis is different from RandomGenerator:getSeed in that getState gets the RandomGenerator's current state, whereas getSeed gets the previously set seed number.\n\nThe value of the state string does not depend on the current operating system.", - returns = "()", - type = "function" - }, - triangulate = { - args = "(polygon: table)", - description = "Triangulate a simple polygon.", - returns = "(triangles: table)", - type = "function" - } - }, - description = "Provides system-independent mathematical functions.", - type = "class" - }, - mouse = { - childs = { - Cursor = { - childs = { - getType = { - args = "()", - description = "Gets the type of the Cursor.", - returns = "(cursortype: CursorType)", - type = "function" - } - }, - description = "Represents a hardware cursor.", - type = "lib" - }, - CursorType = { - childs = { - arrow = { - description = "An arrow pointer.", - type = "value" - }, - crosshair = { - description = "Crosshair symbol.", - type = "value" - }, - hand = { - description = "Hand symbol.", - type = "value" - }, - ibeam = { - description = "An I-beam, normally used when mousing over editable or selectable text.", - type = "value" - }, - image = { - description = "The cursor is using a custom image.", - type = "value" - }, - no = { - description = "Slashed circle or crossbones.", - type = "value" - }, - sizeall = { - description = "Four-pointed arrow pointing up, down, left, and right.", - type = "value" - }, - sizenesw = { - description = "Double arrow pointing to the top-right and bottom-left.", - type = "value" - }, - sizens = { - description = "Double arrow pointing up and down.", - type = "value" - }, - sizenwse = { - description = "Double arrow pointing to the top-left and bottom-right.", - type = "value" - }, - sizewe = { - description = "Double arrow pointing left and right.", - type = "value" - }, - wait = { - description = "Wait graphic.", - type = "value" - }, - waitarrow = { - description = "Small wait cursor with an arrow pointer.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - getPosition = { - args = "()", - description = "Returns the current position of the mouse.", - returns = "(x: number, y: number)", - type = "function" - }, - getRelativeMode = { - args = "()", - description = "Gets whether relative mode is enabled for the mouse.\n\nIf relative mode is enabled, the cursor is hidden and doesn't move when the mouse does, but relative mouse motion events are still generated via love.mousemoved. This lets the mouse move in any direction indefinitely without the cursor getting stuck at the edges of the screen.\n\nThe reported position of the mouse is not updated while relative mode is enabled, even when relative mouse motion events are generated.", - returns = "(enabled: boolean)", - type = "function" - }, - getSystemCursor = { - args = "(ctype: CursorType)", - description = "Gets a Cursor object representing a system-native hardware cursor.\n\n Hardware cursors are framerate-independent and work the same way as normal operating system cursors. Unlike drawing an image at the mouse's current coordinates, hardware cursors never have visible lag between when the mouse is moved and when the cursor position updates, even at low framerates.", - returns = "(cursor: Cursor)", - type = "function" - }, - getX = { - args = "()", - description = "Returns the current x position of the mouse.", - returns = "(x: number)", - type = "function" - }, - getY = { - args = "()", - description = "Returns the current y position of the mouse.", - returns = "(y: number)", - type = "function" - }, - hasCursor = { - args = "()", - description = "Gets whether cursor functionality is supported.\n\nIf it isn't supported, calling love.mouse.newCursor and love.mouse.getSystemCursor will cause an error. Mobile devices do not support cursors.", - returns = "(hascursor: boolean)", - type = "function" - }, - isDown = { - args = "(button: number, ...: number)", - description = "Checks whether a certain mouse button is down. This function does not detect mousewheel scrolling; you must use the love.wheelmoved (or love.mousepressed in version 0.9.2 and older) callback for that.", - returns = "(down: boolean)", - type = "function" - }, - isGrabbed = { - args = "()", - description = "Checks if the mouse is grabbed.", - returns = "(grabbed: boolean)", - type = "function" - }, - isVisible = { - args = "()", - description = "Checks if the cursor is visible.", - returns = "(visible: boolean)", - type = "function" - }, - newCursor = { - args = "(imageData: ImageData, hotx: number, hoty: number)", - description = "Creates a new hardware Cursor object from an image file or ImageData.\n\nHardware cursors are framerate-independent and work the same way as normal operating system cursors. Unlike drawing an image at the mouse's current coordinates, hardware cursors never have visible lag between when the mouse is moved and when the cursor position updates, even at low frameratesn\n\nThe hot spot is the point the operating system uses to determine what was clicked and at what position the mouse cursor is. For example, the normal arrow pointer normally has its hot spot at the top left of the image, but a crosshair cursor might have it in the middle.", - returns = "(cursor: Cursor)", - type = "function" - }, - setCursor = { - args = "(cursor: Cursor)", - description = "Sets the current mouse cursor.\n\nResets the current mouse cursor to the default when called without arguments.", - returns = "()", - type = "function" - }, - setGrabbed = { - args = "(grab: boolean)", - description = "Grabs the mouse and confines it to the window.", - returns = "()", - type = "function" - }, - setPosition = { - args = "(x: number, y: number)", - description = "Sets the position of the mouse.", - returns = "()", - type = "function" - }, - setRelativeMode = { - args = "(enable: boolean)", - description = "Sets whether relative mode is enabled for the mouse.\n\nWhen relative mode is enabled, the cursor is hidden and doesn't move when the mouse does, but relative mouse motion events are still generated via love.mousemoved. This lets the mouse move in any direction indefinitely without the cursor getting stuck at the edges of the screen.\n\nThe reported position of the mouse is not updated while relative mode is enabled, even when relative mouse motion events are generated.", - returns = "()", - type = "function" - }, - setVisible = { - args = "(visible: boolean)", - description = "Sets the visibility of the cursor.", - returns = "()", - type = "function" - }, - setX = { - args = "(x: number)", - description = "Sets the current X position of the mouse.", - returns = "()", - type = "function" - }, - setY = { - args = "(y: number)", - description = "Sets the current Y position of the mouse.", - returns = "()", - type = "function" - } - }, - description = "Provides an interface to the user's mouse.", - type = "class" - }, - mousefocus = { - args = "(f: boolean)", - description = "Callback function triggered when window receives or loses mouse focus.", - returns = "()", - type = "function" - }, - mousemoved = { - args = "(x: number, y: number, dx: number, dy: number)", - description = "Callback function triggered when the mouse is moved.", - returns = "()", - type = "function" - }, - mousepressed = { - args = "(x: number, y: number, button: number, isTouch: boolean)", - description = "Callback function triggered when a mouse button is pressed.", - returns = "()", - type = "function" - }, - mousereleased = { - args = "(x: number, y: number, button: number, isTouch: boolean)", - description = "Callback function triggered when a mouse button is released.", - returns = "()", - type = "function" - }, - physics = { - childs = { - Body = { - childs = { - applyForce = { - args = "(fx: number, fy: number)", - description = "Apply force to a Body.\n\nA force pushes a body in a direction. A body with with a larger mass will react less. The reaction also depends on how long a force is applied: since the force acts continuously over the entire timestep, a short timestep will only push the body for a short time. Thus forces are best used for many timesteps to give a continuous push to a body (like gravity). For a single push that is independent of timestep, it is better to use Body:applyLinearImpulse.\n\nIf the position to apply the force is not given, it will act on the center of mass of the body. The part of the force not directed towards the center of mass will cause the body to spin (and depends on the rotational inertia).\n\nNote that the force components and position must be given in world coordinates.", - returns = "()", - type = "function" - }, - applyLinearImpulse = { - args = "(ix: number, iy: number)", - description = "Applies an impulse to a body. This makes a single, instantaneous addition to the body momentum.\n\nAn impulse pushes a body in a direction. A body with with a larger mass will react less. The reaction does not depend on the timestep, and is equivalent to applying a force continuously for 1 second. Impulses are best used to give a single push to a body. For a continuous push to a body it is better to use Body:applyForce.\n\nIf the position to apply the impulse is not given, it will act on the center of mass of the body. The part of the impulse not directed towards the center of mass will cause the body to spin (and depends on the rotational inertia).\n\nNote that the impulse components and position must be given in world coordinates.", - returns = "()", - type = "function" - }, - applyTorque = { - args = "(torque: number)", - description = "Apply torque to a body.\n\nTorque is like a force that will change the angular velocity (spin) of a body. The effect will depend on the rotational inertia a body has.", - returns = "()", - type = "function" - }, - destroy = { - args = "()", - description = "Explicitly destroys the Body. When you don't have time to wait for garbage collection, this function may be used to free the object immediately, but note that an error will occur if you attempt to use the object after calling this function.", - returns = "()", - type = "function" - }, - getAngle = { - args = "()", - description = "Get the angle of the body.\n\nThe angle is measured in radians. If you need to transform it to degrees, use math.deg.\n\nA value of 0 radians will mean \"looking to the right\". Although radians increase counter-clockwise, the y-axis points down so it becomes clockwise from our point of view.", - returns = "(angle: number)", - type = "function" - }, - getAngularDamping = { - args = "()", - description = "Gets the Angular damping of the Body\n\nThe angular damping is the rate of decrease of the angular velocity over time: A spinning body with no damping and no external forces will continue spinning indefinitely. A spinning body with damping will gradually stop spinning.\n\nDamping is not the same as friction - they can be modelled together. However, only damping is provided by Box2D (and LÖVE).\n\nDamping parameters should be between 0 and infinity, with 0 meaning no damping, and infinity meaning full damping. Normally you will use a damping value between 0 and 0.1.", - returns = "(damping: number)", - type = "function" - }, - getAngularVelocity = { - args = "()", - description = "Get the angular velocity of the Body.\n\nThe angular velocity is the rate of change of angle over time.\n\nIt is changed in World:update by applying torques, off centre forces/impulses, and angular damping. It can be set directly with Body:setAngularVelocity.\n\nIf you need the rate of change of position over time, use Body:getLinearVelocity.", - returns = "(w: number)", - type = "function" - }, - getContactList = { - args = "()", - description = "Gets a list of all Contacts attached to the Body.", - returns = "(contacts: table)", - type = "function" - }, - getFixtureList = { - args = "()", - description = "Returns a table with all fixtures.", - returns = "(fixtures: table)", - type = "function" - }, - getGravityScale = { - args = "()", - description = "Returns the gravity scale factor.", - returns = "(scale: number)", - type = "function" - }, - getInertia = { - args = "()", - description = "Gets the rotational inertia of the body.\n\nThe rotational inertia is how hard is it to make the body spin. It is set with the 4th argument to Body:setMass, or automatically with Body:setMassFromShapes.", - returns = "(inertia: number)", - type = "function" - }, - getJointList = { - args = "()", - description = "Returns a table containing the Joints attached to this Body.", - returns = "(joints: table)", - type = "function" - }, - getLinearDamping = { - args = "()", - description = "Gets the linear damping of the Body.\n\nThe linear damping is the rate of decrease of the linear velocity over time. A moving body with no damping and no external forces will continue moving indefinitely, as is the case in space. A moving body with damping will gradually stop moving.\n\nDamping is not the same as friction - they can be modelled together. However, only damping is provided by Box2D (and LÖVE).", - returns = "(damping: number)", - type = "function" - }, - getLinearVelocity = { - args = "()", - description = "Gets the linear velocity of the Body from its center of mass.\n\nThe linear velocity is the rate of change of position over time.\n\nIf you need the rate of change of angle over time, use Body:getAngularVelocity. If you need to get the linear velocity of a point different from the center of mass:\n\nBody:getLinearVelocityFromLocalPoint allows you to specify the point in local coordinates.\n\nBody:getLinearVelocityFromWorldPoint allows you to specify the point in world coordinates.", - returns = "(x: number, y: number)", - type = "function" - }, - getLinearVelocityFromLocalPoint = { - args = "(x: number, y: number)", - description = "Get the linear velocity of a point on the body.\n\nThe linear velocity for a point on the body is the velocity of the body center of mass plus the velocity at that point from the body spinning.\n\nThe point on the body must given in local coordinates. Use Body:getLinearVelocityFromWorldPoint to specify this with world coordinates.", - returns = "(vx: number, vy: number)", - type = "function" - }, - getLinearVelocityFromWorldPoint = { - args = "(x: number, y: number)", - description = "Get the linear velocity of a point on the body.\n\nThe linear velocity for a point on the body is the velocity of the body center of mass plus the velocity at that point from the body spinning.\n\nThe point on the body must given in world coordinates. Use Body:getLinearVelocityFromLocalPoint to specify this with local coordinates.", - returns = "(vx: number, vy: number)", - type = "function" - }, - getLocalCenter = { - args = "()", - description = "Get the center of mass position in local coordinates.\n\nUse Body:getWorldCenter to get the center of mass in world coordinates.", - returns = "(x: number, y: number)", - type = "function" - }, - getLocalPoint = { - args = "(world_x: number, world_y: number)", - description = "Transform a point from world coordinates to local coordinates.", - returns = "(local_x: number, local_y: number)", - type = "function" - }, - getLocalVector = { - args = "(world_x: number, world_y: number)", - description = "Transform a vector from world coordinates to local coordinates.", - returns = "(local_x: number, local_y: number)", - type = "function" - }, - getMass = { - args = "()", - description = "Get the mass of the body.", - returns = "(mass: number)", - type = "function" - }, - getMassData = { - args = "()", - description = "Returns the mass, its center, and the rotational inertia.", - returns = "(x: number, y: number, mass: number, inertia: number)", - type = "function" - }, - getPosition = { - args = "()", - description = "Get the position of the body.\n\nNote that this may not be the center of mass of the body.", - returns = "(x: number, y: number)", - type = "function" - }, - getType = { - args = "()", - description = "Returns the type of the body.", - returns = "(type: BodyType)", - type = "function" - }, - getUserData = { - args = "()", - description = "Returns the Lua value associated with this Body.\n\nUse this function in one thread only.", - returns = "(value: value)", - type = "function" - }, - getWorld = { - args = "()", - description = "Gets the World the body lives in.", - returns = "(world: World)", - type = "function" - }, - getWorldCenter = { - args = "()", - description = "Get the center of mass position in world coordinates.\n\nUse Body:getLocalCenter to get the center of mass in local coordinates.", - returns = "(x: number, y: number)", - type = "function" - }, - getWorldPoint = { - args = "(local_x: number, local_y: number)", - description = "Transform a point from local coordinates to world coordinates.", - returns = "(world_x: number, world_y: number)", - type = "function" - }, - getWorldPoints = { - args = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - description = "Transforms multiple points from local coordinates to world coordinates.", - returns = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - type = "function" - }, - getWorldVector = { - args = "(local_x: number, local_y: number)", - description = "Transform a vector from local coordinates to world coordinates.", - returns = "(world_x: number, world_y: number)", - type = "function" - }, - getX = { - args = "()", - description = "Get the x position of the body in world coordinates.", - returns = "(x: number)", - type = "function" - }, - getY = { - args = "()", - description = "Get the y position of the body in world coordinates.", - returns = "(y: number)", - type = "function" - }, - isActive = { - args = "()", - description = "Returns whether the body is actively used in the simulation.", - returns = "(status: boolean)", - type = "function" - }, - isAwake = { - args = "()", - description = "Returns the sleep status of the body.", - returns = "(status: boolean)", - type = "function" - }, - isBullet = { - args = "()", - description = "Get the bullet status of a body.\n\nThere are two methods to check for body collisions:\n\nat their location when the world is updated (default)\n\nusing continuous collision detection (CCD)\n\nThe default method is efficient, but a body moving very quickly may sometimes jump over another body without producing a collision. A body that is set as a bullet will use CCD. This is less efficient, but is guaranteed not to jump when moving quickly.\n\nNote that static bodies (with zero mass) always use CCD, so your walls will not let a fast moving body pass through even if it is not a bullet.", - returns = "(status: boolean)", - type = "function" - }, - isDestroyed = { - args = "()", - description = "Gets whether the Body is destroyed. Destroyed bodies cannot be used.", - returns = "(destroyed: boolean)", - type = "function" - }, - isFixedRotation = { - args = "()", - description = "Returns whether the body rotation is locked.", - returns = "(fixed: boolean)", - type = "function" - }, - isSleepingAllowed = { - args = "()", - description = "Returns the sleeping behaviour of the body.", - returns = "(status: boolean)", - type = "function" - }, - resetMassData = { - args = "()", - description = "Resets the mass of the body by recalculating it from the mass properties of the fixtures.", - returns = "()", - type = "function" - }, - setActive = { - args = "(active: boolean)", - description = "Sets whether the body is active in the world.\n\nAn inactive body does not take part in the simulation. It will not move or cause any collisions.", - returns = "()", - type = "function" - }, - setAngle = { - args = "(angle: number)", - description = "Set the angle of the body.\n\nThe angle is measured in radians. If you need to transform it from degrees, use math.rad.\n\nA value of 0 radians will mean \"looking to the right\". .Although radians increase counter-clockwise, the y-axis points down so it becomes clockwise from our point of view.\n\nIt is possible to cause a collision with another body by changing its angle.", - returns = "()", - type = "function" - }, - setAngularDamping = { - args = "(damping: number)", - description = "Sets the angular damping of a Body.\n\nSee Body:getAngularDamping for a definition of angular damping.\n\nAngular damping can take any value from 0 to infinity. It is recommended to stay between 0 and 0.1, though. Other values will look unrealistic.", - returns = "()", - type = "function" - }, - setAngularVelocity = { - args = "(w: number)", - description = "Sets the angular velocity of a Body.\n\nThe angular velocity is the rate of change of angle over time.\n\nThis function will not accumulate anything; any impulses previously applied since the last call to World:update will be lost.", - returns = "()", - type = "function" - }, - setAwake = { - args = "(awake: boolean)", - description = "Wakes the body up or puts it to sleep.", - returns = "()", - type = "function" - }, - setBullet = { - args = "(status: boolean)", - description = "Set the bullet status of a body.\n\nThere are two methods to check for body collisions:\n\nat their location when the world is updated (default)\n\nusing continuous collision detection (CCD)\n\nThe default method is efficient, but a body moving very quickly may sometimes jump over another body without producing a collision. A body that is set as a bullet will use CCD. This is less efficient, but is guaranteed not to jump when moving quickly.\n\nNote that static bodies (with zero mass) always use CCD, so your walls will not let a fast moving body pass through even if it is not a bullet.", - returns = "()", - type = "function" - }, - setFixedRotation = { - args = "(fixed: boolean)", - description = "Set whether a body has fixed rotation.\n\nBodies with fixed rotation don't vary the speed at which they rotate.", - returns = "()", - type = "function" - }, - setGravityScale = { - args = "(scale: number)", - description = "Sets a new gravity scale factor for the body.", - returns = "()", - type = "function" - }, - setInertia = { - args = "(inertia: number)", - description = "Set the inertia of a body.\n\nThis value can also be set by the fourth argument of Body:setMass.", - returns = "()", - type = "function" - }, - setLinearDamping = { - args = "(ld: number)", - description = "Sets the linear damping of a Body\n\nSee Body:getLinearDamping for a definition of linear damping.\n\nLinear damping can take any value from 0 to infinity. It is recommended to stay between 0 and 0.1, though. Other values will make the objects look \"floaty\".", - returns = "()", - type = "function" - }, - setLinearVelocity = { - args = "(x: number, y: number)", - description = "Sets a new linear velocity for the Body.\n\nThis function will not accumulate anything; any impulses previously applied since the last call to World:update will be lost.", - returns = "()", - type = "function" - }, - setMass = { - args = "(mass: number)", - description = "Sets the mass in kilograms.", - returns = "()", - type = "function" - }, - setMassData = { - args = "(x: number, y: number, mass: number, inertia: number)", - description = "Overrides the calculated mass data.", - returns = "()", - type = "function" - }, - setPosition = { - args = "(x: number, y: number)", - description = "Set the position of the body.\n\nNote that this may not be the center of mass of the body.", - returns = "()", - type = "function" - }, - setSleepingAllowed = { - args = "(allowed: boolean)", - description = "Sets the sleeping behaviour of the body.", - returns = "()", - type = "function" - }, - setType = { - args = "(type: BodyType)", - description = "Sets a new body type.", - returns = "()", - type = "function" - }, - setUserData = { - args = "(value: value)", - description = "Associates a Lua value with the Body.\n\nTo delete the reference, explicitly pass nil.\n\nUse this function in one thread only.", - returns = "()", - type = "function" - }, - setX = { - args = "(x: number)", - description = "Set the x position of the body.", - returns = "()", - type = "function" - }, - setY = { - args = "(y: number)", - description = "Set the y position of the body.", - returns = "()", - type = "function" - } - }, - description = "Bodies are objects with velocity and position.", - type = "lib" - }, - BodyType = { - childs = { - dynamic = { - description = "Dynamic bodies collide with all bodies.", - type = "value" - }, - kinematic = { - description = "Kinematic bodies only collide with dynamic bodies.", - type = "value" - }, - static = { - description = "Static bodies do not move.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - ChainShape = { - childs = { - getPoint = { - args = "(index: number)", - description = "Returns a point of the shape.", - returns = "(x: number, y: number)", - type = "function" - }, - getPoints = { - args = "()", - description = "Returns all points of the shape.", - returns = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - type = "function" - }, - getVertexCount = { - args = "()", - description = "Returns the number of vertices the shape has.", - returns = "(count: number)", - type = "function" - }, - setNextVertex = { - args = "(x: number, y: number)", - description = "Sets a vertex that establishes a connection to the next shape.\n\nThis can help prevent unwanted collisions when a flat shape slides along the edge and moves over to the new shape.", - returns = "()", - type = "function" - }, - setPreviousVertex = { - args = "(x: number, y: number)", - description = "Sets a vertex that establishes a connection to the previous shape.\n\nThis can help prevent unwanted collisions when a flat shape slides along the edge and moves over to the new shape.", - returns = "()", - type = "function" - } - }, - description = "A ChainShape consists of multiple line segments. It can be used to create the boundaries of your terrain. The shape does not have volume and can only collide with PolygonShape and CircleShape.\n\nUnlike the PolygonShape, the ChainShape does not have a vertices limit or has to form a convex shape, but self intersections are not supported.", - type = "lib" - }, - CircleShape = { - childs = { - getRadius = { - args = "()", - description = "Gets the radius of the circle shape.", - returns = "(radius: number)", - type = "function" - }, - setPoint = { - args = "(x: number, y: number)", - description = "Sets the location of the center of the circle shape.", - returns = "()", - type = "function" - }, - setRadius = { - args = "(radius: number)", - description = "Sets the radius of the circle.", - returns = "()", - type = "function" - } - }, - description = "Circle extends Shape and adds a radius and a local position.", - type = "lib" - }, - Contact = { - childs = { - getFriction = { - args = "()", - description = "Get the friction between two shapes that are in contact.", - returns = "(friction: number)", - type = "function" - }, - getNormal = { - args = "()", - description = "Get the normal vector between two shapes that are in contact.\n\nThis function returns the coordinates of a unit vector that points from the first shape to the second.", - returns = "(nx: number, ny: number)", - type = "function" - }, - getPositions = { - args = "()", - description = "Returns the contact points of the two colliding fixtures. There can be one or two points.", - returns = "(x1: number, y1: number, x2: number, y2: number)", - type = "function" - }, - getRestitution = { - args = "()", - description = "Get the restitution between two shapes that are in contact.", - returns = "(restitution: number)", - type = "function" - }, - isEnabled = { - args = "()", - description = "Returns whether the contact is enabled. The collision will be ignored if a contact gets disabled in the post solve callback.", - returns = "(enabled: boolean)", - type = "function" - }, - isTouching = { - args = "()", - description = "Returns whether the two colliding fixtures are touching each other.", - returns = "(touching: boolean)", - type = "function" - }, - resetFriction = { - args = "()", - description = "Resets the contact friction to the mixture value of both fixtures.", - returns = "()", - type = "function" - }, - resetRestitution = { - args = "()", - description = "Resets the contact restitution to the mixture value of both fixtures.", - returns = "()", - type = "function" - }, - setEnabled = { - args = "(enabled: boolean)", - description = "Enables or disables the contact.", - returns = "()", - type = "function" - }, - setFriction = { - args = "(friction: number)", - description = "Sets the contact friction.", - returns = "()", - type = "function" - }, - setRestitution = { - args = "(restitution: number)", - description = "Sets the contact restitution.", - returns = "()", - type = "function" - } - }, - description = "Contacts are objects created to manage collisions in worlds.", - type = "lib" - }, - DistanceJoint = { - childs = { - getFrequency = { - args = "()", - description = "Gets the response speed.", - returns = "(Hz: number)", - type = "function" - }, - getLength = { - args = "()", - description = "Gets the equilibrium distance between the two Bodies.", - returns = "(l: number)", - type = "function" - }, - setDampingRatio = { - args = "(ratio: number)", - description = "Sets the damping ratio.", - returns = "()", - type = "function" - }, - setFrequency = { - args = "(Hz: number)", - description = "Sets the response speed.", - returns = "()", - type = "function" - }, - setLength = { - args = "(l: number)", - description = "Sets the equilibrium distance between the two Bodies.", - returns = "()", - type = "function" - } - }, - description = "Keeps two bodies at the same distance.", - type = "lib" - }, - EdgeShape = { - childs = { - getPoints = { - args = "()", - description = "Returns the local coordinates of the edge points.", - returns = "(x1: number, y1: number, x2: number, y2: number)", - type = "function" - } - }, - description = "A EdgeShape is a line segment. They can be used to create the boundaries of your terrain. The shape does not have volume and can only collide with PolygonShape and CircleShape.", - type = "lib" - }, - Fixture = { - childs = { - getBody = { - args = "()", - description = "Returns the body to which the fixture is attached.", - returns = "(body: Body)", - type = "function" - }, - getBoundingBox = { - args = "(index: number)", - description = "Returns the points of the fixture bounding box. In case the fixture has multiple children a 1-based index can be specified. For example, a fixture will have multiple children with a chain shape.", - returns = "(topLeftX: number, topLeftY: number, bottomRightX: number, bottomRightY: number)", - type = "function" - }, - getCategory = { - args = "()", - description = "Returns the categories the fixture belongs to.", - returns = "(category1: number, category2: number, ...: number)", - type = "function" - }, - getDensity = { - args = "()", - description = "Returns the density of the fixture.", - returns = "(density: number)", - type = "function" - }, - getFilterData = { - args = "()", - description = "Returns the filter data of the fixture. Categories and masks are encoded as the bits of a 16-bit integer.", - returns = "(categories: number, mask: number, group: number)", - type = "function" - }, - getFriction = { - args = "()", - description = "Returns the friction of the fixture.", - returns = "(friction: number)", - type = "function" - }, - getGroupIndex = { - args = "()", - description = "Returns the group the fixture belongs to. Fixtures with the same group will always collide if the group is positive or never collide if it's negative. The group zero means no group.\n\nThe groups range from -32768 to 32767.", - returns = "(group: number)", - type = "function" - }, - getMask = { - args = "()", - description = "Returns the category mask of the fixture.", - returns = "(mask1: number, mask2: number, ...: number)", - type = "function" - }, - getMassData = { - args = "()", - description = "Returns the mass, its center and the rotational inertia.", - returns = "(x: number, y: number, mass: number, inertia: number)", - type = "function" - }, - getRestitution = { - args = "()", - description = "Returns the restitution of the fixture.", - returns = "(restitution: number)", - type = "function" - }, - getShape = { - args = "()", - description = "Returns the shape of the fixture. This shape is a reference to the actual data used in the simulation. It's possible to change its values between timesteps.\n\nDo not call any functions on this shape after the parent fixture has been destroyed. This shape will point to an invalid memory address and likely cause crashes if you interact further with it.", - returns = "(shape: Shape)", - type = "function" - }, - getUserData = { - args = "()", - description = "Returns the Lua value associated with this fixture.\n\nUse this function in one thread only.", - returns = "(value: mixed)", - type = "function" - }, - isDestroyed = { - args = "()", - description = "Gets whether the Fixture is destroyed. Destroyed fixtures cannot be used.", - returns = "(destroyed: boolean)", - type = "function" - }, - isSensor = { - args = "()", - description = "Returns whether the fixture is a sensor.", - returns = "(sensor: boolean)", - type = "function" - }, - rayCast = { - args = "(x1: number, y1: number, x2: number, y1: number, maxFraction: number, childIndex: number)", - description = "Casts a ray against the shape of the fixture and returns the surface normal vector and the line position where the ray hit. If the ray missed the shape, nil will be returned.\n\nThe ray starts on the first point of the input line and goes towards the second point of the line. The fourth argument is the maximum distance the ray is going to travel as a scale factor of the input line length.\n\nThe childIndex parameter is used to specify which child of a parent shape, such as a ChainShape, will be ray casted. For ChainShapes, the index of 1 is the first edge on the chain. Ray casting a parent shape will only test the child specified so if you want to test every shape of the parent, you must loop through all of its children.\n\nThe world position of the impact can be calculated by multiplying the line vector with the third return value and adding it to the line starting point.\n\nhitx, hity = x1 + (x2 - x1) * fraction, y1 + (y2 - y1) * fraction", - returns = "(x: number, y: number, fraction: number)", - type = "function" - }, - setCategory = { - args = "(category1: number, category2: number, ...: number)", - description = "Sets the categories the fixture belongs to. There can be up to 16 categories represented as a number from 1 to 16.", - returns = "()", - type = "function" - }, - setDensity = { - args = "(density: number)", - description = "Sets the density of the fixture. Call Body:resetMassData if this needs to take effect immediately.", - returns = "()", - type = "function" - }, - setFilterData = { - args = "(categories: number, mask: number, group: number)", - description = "Sets the filter data of the fixture.\n\nGroups, categories, and mask can be used to define the collision behaviour of the fixture.\n\nIf two fixtures are in the same group they either always collide if the group is positive, or never collide if it's negative. Is the group zero or they do not match, then the contact filter checks if the fixtures select a category of the other fixture with their masks. The fixtures do not collide if that's not the case. If they do have each others categories selected, the return value of the custom contact filter will be used. They always collide if none was set.\n\nThere can be up to 16 categories. Categories and masks are encoded as the bits of a 16-bit integer.", - returns = "()", - type = "function" - }, - setFriction = { - args = "(friction: number)", - description = "Sets the friction of the fixture.", - returns = "()", - type = "function" - }, - setGroupIndex = { - args = "(group: number)", - description = "Sets the group the fixture belongs to. Fixtures with the same group will always collide if the group is positive or never collide if it's negative. The group zero means no group.\n\nThe groups range from -32768 to 32767.", - returns = "()", - type = "function" - }, - setMask = { - args = "(mask1: number, mask2: number, ...: number)", - description = "Sets the category mask of the fixture. There can be up to 16 categories represented as a number from 1 to 16.\n\nThis fixture will collide with the fixtures that are in the selected categories if the other fixture also has a category of this fixture selected.", - returns = "()", - type = "function" - }, - setRestitution = { - args = "(restitution: number)", - description = "Sets the restitution of the fixture.", - returns = "()", - type = "function" - }, - setSensor = { - args = "(sensor: boolean)", - description = "Sets whether the fixture should act as a sensor.\n\nSensor do not produce collisions responses, but the begin and end callbacks will still be called for this fixture.", - returns = "()", - type = "function" - }, - setUserData = { - args = "(value: mixed)", - description = "Associates a Lua value with the fixture.\n\nUse this function in one thread only.", - returns = "()", - type = "function" - }, - testPoint = { - args = "(x: number, y: number)", - description = "Checks if a point is inside the shape of the fixture.", - returns = "(isInside: boolean)", - type = "function" - } - }, - description = "Fixtures attach shapes to bodies.", - type = "lib" - }, - FrictionJoint = { - childs = { - getMaxTorque = { - args = "()", - description = "Gets the maximum friction torque in Newton-meters.", - returns = "(torque: number)", - type = "function" - }, - setMaxForce = { - args = "(maxForce: number)", - description = "Sets the maximum friction force in Newtons.", - returns = "()", - type = "function" - }, - setMaxTorque = { - args = "(torque: number)", - description = "Sets the maximum friction torque in Newton-meters.", - returns = "()", - type = "function" - } - }, - description = "A FrictionJoint applies friction to a body.", - type = "lib" - }, - GearJoint = { - childs = { - getRatio = { - args = "()", - description = "Get the ratio of a gear joint.", - returns = "(ratio: number)", - type = "function" - }, - setRatio = { - args = "(ratio: number)", - description = "Set the ratio of a gear joint.", - returns = "()", - type = "function" - } - }, - description = "Keeps bodies together in such a way that they act like gears.", - type = "lib" - }, - Joint = { - childs = { - getAnchors = { - args = "()", - description = "Get the anchor points of the joint.", - returns = "(x1: number, y1: number, x2: number, y2: number)", - type = "function" - }, - getBodies = { - args = "()", - description = "Gets the bodies that the Joint is attached to.", - returns = "(bodyA: Body, bodyB: Body)", - type = "function" - }, - getCollideConnected = { - args = "()", - description = "Gets whether the connected Bodies collide.", - returns = "(c: boolean)", - type = "function" - }, - getReactionForce = { - args = "()", - description = "Gets the reaction force on Body 2 at the joint anchor.", - returns = "(x: number, y: number)", - type = "function" - }, - getReactionTorque = { - args = "(invdt: number)", - description = "Returns the reaction torque on the second body.", - returns = "(torque: number)", - type = "function" - }, - getType = { - args = "()", - description = "Gets an string representing the type.", - returns = "(type: JointType)", - type = "function" - }, - getUserData = { - args = "()", - description = "Returns the Lua value associated with this Joint.", - returns = "(value: mixed)", - type = "function" - }, - isDestroyed = { - args = "()", - description = "Gets whether the Joint is destroyed. Destroyed joints cannot be used.", - returns = "(destroyed: boolean)", - type = "function" - }, - setCollideConnected = { - args = "(collide: boolean)", - description = "Sets whether the connected Bodies should collide with eachother.", - returns = "()", - type = "function" - }, - setUserData = { - args = "(value: mixed)", - description = "Associates a Lua value with the Joint.\n\nTo delete the reference, explicitly pass nil.", - returns = "()", - type = "function" - } - }, - description = "Attach multiple bodies together to interact in unique ways.", - type = "lib" - }, - JointType = { - childs = { - distance = { - description = "A DistanceJoint.", - type = "value" - }, - friction = { - description = "A FrictionJoint.", - type = "value" - }, - gear = { - description = "A GearJoint.", - type = "value" - }, - mouse = { - description = "A MouseJoint.", - type = "value" - }, - prismatic = { - description = "A PrismaticJoint.", - type = "value" - }, - pulley = { - description = "A PulleyJoint.", - type = "value" - }, - revolute = { - description = "A RevoluteJoint.", - type = "value" - }, - rope = { - description = "A RopeJoint.", - type = "value" - }, - weld = { - description = "A WeldJoint.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - MouseJoint = { - childs = { - getFrequency = { - args = "()", - description = "Returns the frequency.", - returns = "(freq: number)", - type = "function" - }, - getMaxForce = { - args = "()", - description = "Gets the highest allowed force.", - returns = "(f: number)", - type = "function" - }, - getTarget = { - args = "()", - description = "Gets the target point.", - returns = "(x: number, y: number)", - type = "function" - }, - setDampingRatio = { - args = "(ratio: number)", - description = "Sets a new damping ratio.", - returns = "()", - type = "function" - }, - setFrequency = { - args = "(freq: number)", - description = "Sets a new frequency.", - returns = "()", - type = "function" - }, - setMaxForce = { - args = "(f: number)", - description = "Sets the highest allowed force.", - returns = "()", - type = "function" - }, - setTarget = { - args = "(x: number, y: number)", - description = "Sets the target point.", - returns = "()", - type = "function" - } - }, - description = "For controlling objects with the mouse.", - type = "lib" - }, - PolygonShape = { - childs = { - getPoints = { - args = "()", - description = "Get the local coordinates of the polygon's vertices.\n\nThis function has a variable number of return values. It can be used in a nested fashion with love.graphics.polygon.\n\nThis function may have up to 16 return values, since it returns two values for each vertex in the polygon. In other words, it can return the coordinates of up to 8 points.", - returns = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - type = "function" - } - }, - description = "Polygon is a convex polygon with up to 8 sides.", - type = "lib" - }, - PrismaticJoint = { - childs = { - getJointSpeed = { - args = "()", - description = "Get the current joint angle speed.", - returns = "(s: number)", - type = "function" - }, - getJointTranslation = { - args = "()", - description = "Get the current joint translation.", - returns = "(t: number)", - type = "function" - }, - getLimits = { - args = "()", - description = "Gets the joint limits.", - returns = "(lower: number, upper: number)", - type = "function" - }, - getLowerLimit = { - args = "()", - description = "Gets the lower limit.", - returns = "(lower: number)", - type = "function" - }, - getMaxMotorForce = { - args = "()", - description = "Gets the maximum motor force.", - returns = "(f: number)", - type = "function" - }, - getMotorForce = { - args = "()", - description = "Get the current motor force.", - returns = "(f: number)", - type = "function" - }, - getMotorSpeed = { - args = "()", - description = "Gets the motor speed.", - returns = "(s: number)", - type = "function" - }, - getUpperLimit = { - args = "()", - description = "Gets the upper limit.", - returns = "(upper: number)", - type = "function" - }, - hasLimitsEnabled = { - args = "()", - description = "Checks whether the limits are enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - isMotorEnabled = { - args = "()", - description = "Checks whether the motor is enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - setLimits = { - args = "(lower: number, upper: number)", - description = "Sets the limits.", - returns = "()", - type = "function" - }, - setLowerLimit = { - args = "(lower: number)", - description = "Sets the lower limit.", - returns = "()", - type = "function" - }, - setMaxMotorForce = { - args = "(f: number)", - description = "Set the maximum motor force.", - returns = "()", - type = "function" - }, - setMotorEnabled = { - args = "(enable: boolean)", - description = "Starts or stops the joint motor.", - returns = "()", - type = "function" - }, - setMotorSpeed = { - args = "(s: number)", - description = "Sets the motor speed.", - returns = "()", - type = "function" - }, - setUpperLimit = { - args = "(upper: number)", - description = "Sets the upper limit.", - returns = "()", - type = "function" - } - }, - description = "Restricts relative motion between Bodies to one shared axis.", - type = "lib" - }, - PulleyJoint = { - childs = { - getGroundAnchors = { - args = "()", - description = "Get the ground anchor positions in world coordinates.", - returns = "(a1x: number, a1y: number, a2x: number, a2y: number)", - type = "function" - }, - getLengthA = { - args = "()", - description = "Get the current length of the rope segment attached to the first body.", - returns = "(length: number)", - type = "function" - }, - getLengthB = { - args = "()", - description = "Get the current length of the rope segment attached to the second body.", - returns = "(length: number)", - type = "function" - }, - getMaxLengths = { - args = "()", - description = "Get the maximum lengths of the rope segments.", - returns = "(len1: number, len2: number)", - type = "function" - }, - getRatio = { - args = "()", - description = "Get the pulley ratio.", - returns = "(ratio: number)", - type = "function" - }, - setConstant = { - args = "(length: number)", - description = "Set the total length of the rope.\n\nSetting a new length for the rope updates the maximum length values of the joint.", - returns = "()", - type = "function" - }, - setMaxLengths = { - args = "(max1: number, max2: number)", - description = "Set the maximum lengths of the rope segments.\n\nThe physics module also imposes maximum values for the rope segments. If the parameters exceed these values, the maximum values are set instead of the requested values.", - returns = "()", - type = "function" - }, - setRatio = { - args = "(ratio: number)", - description = "Set the pulley ratio.", - returns = "()", - type = "function" - } - }, - description = "Allows you to simulate bodies connected through pulleys.", - type = "lib" - }, - RevoluteJoint = { - childs = { - getJointAngle = { - args = "()", - description = "Get the current joint angle.", - returns = "(angle: number)", - type = "function" - }, - getJointSpeed = { - args = "()", - description = "Get the current joint angle speed.", - returns = "(s: number)", - type = "function" - }, - getLimits = { - args = "()", - description = "Gets the joint limits.", - returns = "(lower: number, upper: number)", - type = "function" - }, - getLowerLimit = { - args = "()", - description = "Gets the lower limit.", - returns = "(lower: number)", - type = "function" - }, - getMaxMotorTorque = { - args = "()", - description = "Gets the maximum motor force.", - returns = "(f: number)", - type = "function" - }, - getMotorSpeed = { - args = "()", - description = "Gets the motor speed.", - returns = "(s: number)", - type = "function" - }, - getMotorTorque = { - args = "()", - description = "Get the current motor force.", - returns = "(f: number)", - type = "function" - }, - getUpperLimit = { - args = "()", - description = "Gets the upper limit.", - returns = "(upper: number)", - type = "function" - }, - hasLimitsEnabled = { - args = "()", - description = "Checks whether limits are enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - isMotorEnabled = { - args = "()", - description = "Checks whether the motor is enabled.", - returns = "(enabled: boolean)", - type = "function" - }, - setLimits = { - args = "(lower: number, upper: number)", - description = "Sets the limits.", - returns = "()", - type = "function" - }, - setLowerLimit = { - args = "(lower: number)", - description = "Sets the lower limit.", - returns = "()", - type = "function" - }, - setMaxMotorTorque = { - args = "(f: number)", - description = "Set the maximum motor force.", - returns = "()", - type = "function" - }, - setMotorEnabled = { - args = "(enable: boolean)", - description = "Starts or stops the joint motor.", - returns = "()", - type = "function" - }, - setMotorSpeed = { - args = "(s: number)", - description = "Sets the motor speed.", - returns = "()", - type = "function" - }, - setUpperLimit = { - args = "(upper: number)", - description = "Sets the upper limit.", - returns = "()", - type = "function" - } - }, - description = "Allow two Bodies to revolve around a shared point.", - type = "lib" - }, - RopeJoint = { - childs = { - getMaxLength = { - args = "()", - description = "Gets the maximum length of a RopeJoint.", - returns = "(maxLength: number)", - type = "function" - } - }, - description = "The RopeJoint enforces a maximum distance between two points on two bodies. It has no other effect.", - type = "lib" - }, - Shape = { - childs = { - computeMass = { - args = "(density: number)", - description = "Computes the mass properties for the shape with the specified density.", - returns = "(x: number, y: number, mass: number, inertia: number)", - type = "function" - }, - getChildCount = { - args = "()", - description = "Returns the number of children the shape has.", - returns = "(count: number)", - type = "function" - }, - getRadius = { - args = "()", - description = "Gets the radius of the shape.", - returns = "(radius: number)", - type = "function" - }, - getType = { - args = "()", - description = "Gets a string representing the Shape. This function can be useful for conditional debug drawing.", - returns = "(type: ShapeType)", - type = "function" - }, - rayCast = { - args = "(x1: number, y1: number, x2: number, y2: number, maxFraction: number, tx: number, ty: number, tr: number, childIndex: number)", - description = "Casts a ray against the shape and returns the surface normal vector and the line position where the ray hit. If the ray missed the shape, nil will be returned. The Shape can be transformed to get it into the desired position.\n\nThe ray starts on the first point of the input line and goes towards the second point of the line. The fourth argument is the maximum distance the ray is going to travel as a scale factor of the input line length.\n\nThe childIndex parameter is used to specify which child of a parent shape, such as a ChainShape, will be ray casted. For ChainShapes, the index of 1 is the first edge on the chain. Ray casting a parent shape will only test the child specified so if you want to test every shape of the parent, you must loop through all of its children.\n\nThe world position of the impact can be calculated by multiplying the line vector with the third return value and adding it to the line starting point.\n\nhitx, hity = x1 + (x2 - x1) * fraction, y1 + (y2 - y1) * fraction", - returns = "(xn: number, yn: number, fraction: number)", - type = "function" - }, - testPoint = { - args = "(x: number, y: number)", - description = "Checks whether a point lies inside the shape. This is particularly useful for mouse interaction with the shapes. By looping through all shapes and testing the mouse position with this function, we can find which shapes the mouse touches.", - returns = "(hit: boolean)", - type = "function" - } - }, - description = "Shapes are solid 2d geometrical objects used in love.physics.\n\nShapes are attached to a Body via a Fixture. The Shape object is copied when this happens. Shape position is relative to Body position.", - type = "lib" - }, - ShapeType = { - childs = { - chain = { - description = "The Shape is a ChainShape.", - type = "value" - }, - circle = { - description = "The Shape is a CircleShape.", - type = "value" - }, - edge = { - description = "The Shape is a EdgeShape.", - type = "value" - }, - polygon = { - description = "The Shape is a PolygonShape.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - WeldJoint = { - childs = { - getFrequency = { - args = "()", - description = "Returns the frequency.", - returns = "(freq: number)", - type = "function" - }, - setDampingRatio = { - args = "(ratio: number)", - description = "The new damping ratio.", - returns = "()", - type = "function" - }, - setFrequency = { - args = "(freq: number)", - description = "Sets a new frequency.", - returns = "()", - type = "function" - } - }, - description = "A WeldJoint essentially glues two bodies together.", - type = "lib" - }, - WheelJoint = { - childs = { - getJointTranslation = { - args = "()", - description = "Returns the current joint translation.", - returns = "(position: number)", - type = "function" - }, - getLimits = { - args = "()", - description = "Gets the joint limits.", - returns = "(lower: number, upper: number)", - type = "function" - }, - getMaxMotorTorque = { - args = "()", - description = "Returns the maximum motor torque.", - returns = "(maxTorque: number)", - type = "function" - }, - getMotorSpeed = { - args = "()", - description = "Returns the speed of the motor.", - returns = "(speed: number)", - type = "function" - }, - getMotorTorque = { - args = "(invdt: number)", - description = "Returns the current torque on the motor.", - returns = "(torque: number)", - type = "function" - }, - getSpringDampingRatio = { - args = "()", - description = "Returns the damping ratio.", - returns = "(ratio: number)", - type = "function" - }, - getSpringFrequency = { - args = "()", - description = "Returns the spring frequency.", - returns = "(freq: number)", - type = "function" - }, - setMaxMotorTorque = { - args = "(maxTorque: number)", - description = "Sets a new maximum motor torque.", - returns = "()", - type = "function" - }, - setMotorEnabled = { - args = "(enable: boolean)", - description = "Starts and stops the joint motor.", - returns = "()", - type = "function" - }, - setMotorSpeed = { - args = "(speed: number)", - description = "Sets a new speed for the motor.", - returns = "()", - type = "function" - }, - setSpringDampingRatio = { - args = "(ratio: number)", - description = "Sets a new damping ratio.", - returns = "()", - type = "function" - }, - setSpringFrequency = { - args = "(freq: number)", - description = "Sets a new spring frequency.", - returns = "()", - type = "function" - } - }, - description = "Restricts a point on the second body to a line on the first body.", - type = "lib" - }, - World = { - childs = { - getBodyCount = { - args = "()", - description = "Get the number of bodies in the world.", - returns = "(n: number)", - type = "function" - }, - getBodyList = { - args = "()", - description = "Returns a table with all bodies.", - returns = "(bodies: table)", - type = "function" - }, - getCallbacks = { - args = "()", - description = "Returns functions for the callbacks during the world update.", - returns = "(beginContact: function, endContact: function, preSolve: function, postSolve: function)", - type = "function" - }, - getContactCount = { - args = "()", - description = "Returns the number of contacts in the world.", - returns = "(n: number)", - type = "function" - }, - getContactFilter = { - args = "()", - description = "Returns the function for collision filtering.", - returns = "(contactFilter: function)", - type = "function" - }, - getContactList = { - args = "()", - description = "Returns a table with all contacts.", - returns = "(contacts: table)", - type = "function" - }, - getGravity = { - args = "()", - description = "Get the gravity of the world.", - returns = "(x: number, y: number)", - type = "function" - }, - getJointCount = { - args = "()", - description = "Get the number of joints in the world.", - returns = "(n: number)", - type = "function" - }, - getJointList = { - args = "()", - description = "Returns a table with all joints.", - returns = "(joints: table)", - type = "function" - }, - isDestroyed = { - args = "()", - description = "Gets whether the World is destroyed. Destroyed worlds cannot be used.", - returns = "(destroyed: boolean)", - type = "function" - }, - isLocked = { - args = "()", - description = "Returns if the world is updating its state.\n\nThis will return true inside the callbacks from World:setCallbacks.", - returns = "(locked: boolean)", - type = "function" - }, - isSleepingAllowed = { - args = "()", - description = "Returns the sleep behaviour of the world.", - returns = "(allowSleep: boolean)", - type = "function" - }, - queryBoundingBox = { - args = "(topLeftX: number, topLeftY: number, bottomRightX: number, bottomRightY: number, callback: function)", - description = "Calls a function for each fixture inside the specified area.", - returns = "()", - type = "function" - }, - rayCast = { - args = "(x1: number, y1: number, x2: number, y2: number, callback: function)", - description = "Casts a ray and calls a function with the fixtures that intersect it. You cannot make any assumptions about the order of the callbacks.\n\nEach time the function gets called, 6 arguments get passed to it. The first is the fixture intersecting the ray. The second and third are the coordinates of the intersection point. The fourth and fifth is the surface normal vector of the shape edge. The sixth argument is the position of the intersection on the ray as a number from 0 to 1 (or even higher if the ray length was changed with the return value).\n\nThe ray can be controlled with the return value. A positive value sets a new ray length where 1 is the default value. A value of 0 terminates the ray. If the callback function returns -1, the intersection gets ignored as if it didn't happen.\n\nThere is a bug in 0.8.0 where the normal vector passed to the callback function gets scaled by love.physics.getMeter.", - returns = "()", - type = "function" - }, - setCallbacks = { - args = "(beginContact: function, endContact: function, preSolve: function, postSolve: function)", - description = "Sets functions for the collision callbacks during the world update.\n\nFour Lua functions can be given as arguments. The value nil removes a function.\n\nWhen called, each function will be passed three arguments. The first two arguments are the colliding fixtures and the third argument is the Contact between them. The PostSolve callback additionally gets the normal and tangent impulse for each contact point.", - returns = "()", - type = "function" - }, - setContactFilter = { - args = "(filter: function)", - description = "Sets a function for collision filtering.\n\nIf the group and category filtering doesn't generate a collision decision, this function gets called with the two fixtures as arguments. The function should return a boolean value where true means the fixtures will collide and false means they will pass through each other.", - returns = "()", - type = "function" - }, - setGravity = { - args = "(x: number, y: number)", - description = "Set the gravity of the world.", - returns = "()", - type = "function" - }, - setSleepingAllowed = { - args = "(allowSleep: boolean)", - description = "Set the sleep behaviour of the world.\n\nA sleeping body is much more efficient to simulate than when awake.\n\nIf sleeping is allowed, any body that has come to rest will sleep.", - returns = "()", - type = "function" - }, - translateOrigin = { - args = "(x: number, y: number)", - description = "Translates the World's origin. Useful in large worlds where floating point precision issues become noticeable at far distances from the origin.", - returns = "()", - type = "function" - }, - update = { - args = "(dt: number)", - description = "Update the state of the world.", - returns = "()", - type = "function" - } - }, - description = "A world is an object that contains all bodies and joints.", - type = "lib" - }, - getMeter = { - args = "()", - description = "Get the scale of the world.\n\nThe world scale is the number of pixels per meter. Try to keep your shape sizes less than 10 times this scale.\n\nThis is important because the physics in Box2D is tuned to work well for objects of size 0.1m up to 10m. All physics coordinates are divided by this number for the physics calculations.", - returns = "(scale: number)", - type = "function" - }, - newBody = { - args = "(world: World, x: number, y: number, type: BodyType)", - description = "Creates a new body.\n\nThere are three types of bodies. Static bodies do not move, have a infinite mass, and can be used for level boundaries. Dynamic bodies are the main actors in the simulation, they collide with everything. Kinematic bodies do not react to forces and only collide with dynamic bodies.\n\nThe mass of the body gets calculated when a Fixture is attached or removed, but can be changed at any time with Body:setMass or Body:resetMassData.", - returns = "(body: Body)", - type = "function" - }, - newChainShape = { - args = "(loop: boolean, x1: number, y1: number, x2: number, y2: number, ...: number)", - description = "Creates a new ChainShape.", - returns = "(shape: ChainShape)", - type = "function" - }, - newCircleShape = { - args = "(radius: number)", - description = "Creates a new CircleShape.", - returns = "(shape: CircleShape)", - type = "function" - }, - newDistanceJoint = { - args = "(body1: Body, body2: Body, x1: number, y1: number, x2: number, y2: number, collideConnected: boolean)", - description = "Create a distance joint between two bodies.\n\nThis joint constrains the distance between two points on two bodies to be constant. These two points are specified in world coordinates and the two bodies are assumed to be in place when this joint is created. The first anchor point is connected to the first body and the second to the second body, and the points define the length of the distance joint.", - returns = "(joint: DistanceJoint)", - type = "function" - }, - newEdgeShape = { - args = "(x1: number, y1: number, x2: number, y2: number)", - description = "Creates a edge shape.", - returns = "(shape: EdgeShape)", - type = "function" - }, - newFixture = { - args = "(body: Body, shape: Shape, density: number)", - description = "Creates and attaches a Fixture to a body.", - returns = "(fixture: Fixture)", - type = "function" - }, - newFrictionJoint = { - args = "(body1: Body, body2: Body, x: number, y: number, collideConnected: boolean)", - description = "Create a friction joint between two bodies. A FrictionJoint applies friction to a body.", - returns = "(joint: FrictionJoint)", - type = "function" - }, - newGearJoint = { - args = "(joint1: Joint, joint2: Joint, ratio: number, collideConnected: boolean)", - description = "Create a gear joint connecting two joints.\n\nThe gear joint connects two joints that must be either prismatic or revolute joints. Using this joint requires that the joints it uses connect their respective bodies to the ground and have the ground as the first body. When destroying the bodies and joints you must make sure you destroy the gear joint before the other joints.\n\nThe gear joint has a ratio the determines how the angular or distance values of the connected joints relate to each other. The formula coordinate1 + ratio * coordinate2 always has a constant value that is set when the gear joint is created.", - returns = "(joint: Joint)", - type = "function" - }, - newMouseJoint = { - args = "(body: Body, x: number, y: number)", - description = "Create a joint between a body and the mouse.\n\nThis joint actually connects the body to a fixed point in the world. To make it follow the mouse, the fixed point must be updated every timestep (example below).\n\nThe advantage of using a MouseJoint instead of just changing a body position directly is that collisions and reactions to other joints are handled by the physics engine.", - returns = "(joint: Joint)", - type = "function" - }, - newPolygonShape = { - args = "(x1: number, y1: number, x2: number, y2: number, ...: number)", - description = "Creates a new PolygonShape.\n\nThis shape can have 8 vertices at most, and must form a convex shape.", - returns = "(shape: PolygonShape)", - type = "function" - }, - newPrismaticJoint = { - args = "(body1: Body, body2: Body, x: number, y: number, ax: number, ay: number, collideConnected: boolean)", - description = "Create a prismatic joints between two bodies.\n\nA prismatic joint constrains two bodies to move relatively to each other on a specified axis. It does not allow for relative rotation. Its definition and operation are similar to a revolute joint, but with translation and force substituted for angle and torque.", - returns = "(joint: PrismaticJoint)", - type = "function" - }, - newPulleyJoint = { - args = "(body1: Body, body2: Body, gx1: number, gy1: number, gx2: number, gy2: number, x1: number, y1: number, x2: number, y2: number, ratio: number, collideConnected: boolean)", - description = "Create a pulley joint to join two bodies to each other and the ground.\n\nThe pulley joint simulates a pulley with an optional block and tackle. If the ratio parameter has a value different from one, then the simulated rope extends faster on one side than the other. In a pulley joint the total length of the simulated rope is the constant length1 + ratio * length2, which is set when the pulley joint is created.\n\nPulley joints can behave unpredictably if one side is fully extended. It is recommended that the method setMaxLengths be used to constrain the maximum lengths each side can attain.", - returns = "(joint: Joint)", - type = "function" - }, - newRectangleShape = { - args = "(width: number, height: number)", - description = "Shorthand for creating rectangluar PolygonShapes.\n\nBy default, the local origin is located at the center of the rectangle as opposed to the top left for graphics.", - returns = "(shape: PolygonShape)", - type = "function" - }, - newRevoluteJoint = { - args = "(body1: Body, body2: Body, x: number, y: number, collideConnected: number)", - description = "Creates a pivot joint between two bodies.\n\nThis joint connects two bodies to a point around which they can pivot.", - returns = "(joint: Joint)", - type = "function" - }, - newRopeJoint = { - args = "(body1: Body, body2: Body, x1: number, y1: number, x2: number, y2: number, maxLength: number, collideConnected: boolean)", - description = "Create a joint between two bodies. Its only function is enforcing a max distance between these bodies.", - returns = "(joint: RopeJoint)", - type = "function" - }, - newWeldJoint = { - args = "(body1: Body, body2: Body, x: number, y: number, collideConnected: boolean)", - description = "Create a friction joint between two bodies. A WeldJoint essentially glues two bodies together.", - returns = "(joint: WeldJoint)", - type = "function" - }, - newWheelJoint = { - args = "(body1: Body, body2: Body, x: number, y: number, ax: number, ay: number, collideConnected: boolean)", - description = "Creates a wheel joint.", - returns = "(joint: WheelJoint)", - type = "function" - }, - newWorld = { - args = "(xg: number, yg: number, sleep: boolean)", - description = "Creates a new World.", - returns = "(world: World)", - type = "function" - }, - setMeter = { - args = "(scale: number)", - description = "Sets the pixels to meter scale factor.\n\nAll coordinates in the physics module are divided by this number and converted to meters, and it creates a convenient way to draw the objects directly to the screen without the need for graphics transformations.\n\nIt is recommended to create shapes no larger than 10 times the scale. This is important because Box2D is tuned to work well with shape sizes from 0.1 to 10 meters. The default meter scale is 30.\n\nlove.physics.setMeter does not apply retroactively to created objects. Created objects retain their meter coordinates but the scale factor will affect their pixel coordinates.", - returns = "()", - type = "function" - } - }, - description = "Can simulate 2D rigid body physics in a realistic manner. This module is based on Box2D, and this API corresponds to the Box2D API as closely as possible.", - type = "class" - }, - quit = { - args = "()", - description = "Callback function triggered when the game is closed.", - returns = "(r: boolean)", - type = "function" - }, - resize = { - args = "(w: number, h: number)", - description = "Called when the window is resized, for example if the user resizes the window, or if love.window.setMode is called with an unsupported width or height in fullscreen and the window chooses the closest appropriate size.\n\nCalls to love.window.setMode will only trigger this event if the width or height of the window after the call doesn't match the requested width and height. This can happen if a fullscreen mode is requested which doesn't match any supported mode, or if the fullscreen type is 'desktop' and the requested width or height don't match the desktop resolution.", - returns = "()", - type = "function" - }, - run = { - args = "()", - description = "The main function, containing the main loop. A sensible default is used when left out.", - returns = "()", - type = "function" - }, - sound = { - childs = { - Decoder = { - childs = { - getChannels = { - args = "()", - description = "Returns the number of channels in the stream.", - returns = "(channels: number)", - type = "function" - }, - getDuration = { - args = "()", - description = "Gets the duration of the sound file. It may not always be sample-accurate, and it may return -1 if the duration cannot be determined at all.", - returns = "(duration: number)", - type = "function" - }, - getSampleRate = { - args = "()", - description = "Returns the sample rate of the Decoder.", - returns = "(rate: number)", - type = "function" - } - }, - description = "An object which can gradually decode a sound file.", - type = "lib" - }, - SoundData = { - childs = { - getChannels = { - args = "()", - description = "Returns the number of channels in the stream.", - returns = "(channels: number)", - type = "function" - }, - getDuration = { - args = "()", - description = "Returns the number of channels in the stream.", - returns = "(duration: number)", - type = "function" - }, - getSample = { - args = "(i: number)", - description = "Gets the sample at the specified position.", - returns = "(sample: number)", - type = "function" - }, - getSampleCount = { - args = "()", - description = "Returns the sample count of the SoundData.", - returns = "(count: number)", - type = "function" - }, - getSampleRate = { - args = "()", - description = "Returns the sample rate of the SoundData.", - returns = "(rate: number)", - type = "function" - }, - setSample = { - args = "(i: number, sample: number)", - description = "Sets the sample at the specified position.", - returns = "()", - type = "function" - } - }, - description = "Contains raw audio samples. You can not play SoundData back directly. You must wrap a Source object around it.", - type = "lib" - }, - newSoundData = { - args = "(filename: string)", - description = "Creates new SoundData from a file. It's also possible to create SoundData with a custom sample rate, channel and bit depth.\n\nThe sound data will be decoded to the memory in a raw format. It is recommended to create only short sounds like effects, as a 3 minute song uses 30 MB of memory this way.", - returns = "(soundData: SoundData)", - type = "function" - } - }, - description = "This module is responsible for decoding sound files. It can't play the sounds, see love.audio for that.", - type = "class" - }, - system = { - childs = { - PowerState = { - childs = { - battery = { - description = "Not plugged in, running on a battery.", - type = "value" - }, - charged = { - description = "Plugged in, battery is fully charged.", - type = "value" - }, - charging = { - description = "Plugged in, charging battery.", - type = "value" - }, - nobattery = { - description = "Plugged in, no battery available.", - type = "value" - }, - unknown = { - description = "Cannot determine power status.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - getOS = { - args = "()", - description = "Gets the current operating system. In general, LÖVE abstracts away the need to know the current operating system, but there are a few cases where it can be useful (especially in combination with os.execute.)", - returns = "(os_string: string)", - type = "function" - }, - getPowerInfo = { - args = "()", - description = "Gets information about the system's power supply.", - returns = "(state: PowerState, percent: number, seconds: number)", - type = "function" - }, - getProcessorCount = { - args = "()", - description = "Gets the number of CPU cores in the system.\n\nThe number includes the threads reported if technologies such as Intel's Hyper-threading are enabled. For example, on a 4-core CPU with Hyper-threading, this function will return 8.", - returns = "(cores: number)", - type = "function" - }, - openURL = { - args = "(url: string)", - description = "Opens a URL with the user's web or file browser.", - returns = "(success: boolean)", - type = "function" - }, - setClipboardText = { - args = "(text: string)", - description = "Puts text in the clipboard.", - returns = "()", - type = "function" - }, - vibrate = { - args = "(seconds: number)", - description = "Causes the device to vibrate, if possible. Currently this will only work on Android and iOS devices that have a built-in vibration motor.", - returns = "()", - type = "function" - } - }, - description = "Provides access to information about the user's system.", - type = "lib" - }, - textedited = { - args = "(text: string, start: number, length: number)", - description = "Called when the candidate text for an IME (Input Method Editor) has changed.\n\nThe candidate text is not the final text that the user will eventually choose. Use love.textinput for that.", - returns = "()", - type = "function" - }, - textinput = { - args = "(text: string)", - description = "Called when text has been entered by the user. For example if shift-2 is pressed on an American keyboard layout, the text \"@\" will be generated.", - returns = "()", - type = "function" - }, - thread = { - childs = { - Channel = { - childs = { - demand = { - args = "()", - description = "Retrieves the value of a Channel message and removes it from the message queue.\n\nThe value of the message can be a boolean, string, number, LÖVE userdata, or a simple flat table. It waits until a message is in the queue then returns the message value.", - returns = "(value: value)", - type = "function" - }, - getCount = { - args = "()", - description = "Retrieves the number of messages in the thread Channel queue.", - returns = "(count: number)", - type = "function" - }, - peek = { - args = "()", - description = "Retrieves the value of a Channel message, but leaves it in the queue.\n\nThe value of the message can be a boolean, string, number or a LÖVE userdata. It returns nil if there's no message in the queue.", - returns = "(value: value)", - type = "function" - }, - performAtomic = { - args = "(func: function, arg1: any, ...: any)", - description = "Executes the specified function atomically with respect to this Channel.\n\nCalling multiple methods in a row on the same Channel is often useful. However if multiple Threads are calling this Channel's methods at the same time, the different calls on each Thread might end up interleaved (e.g. one or more of the second thread's calls may happen in between the first thread's calls.)\n\nThis method avoids that issue by making sure the Thread calling the method has exclusive access to the Channel until the specified function has returned.", - returns = "(ret1: any, ...: any)", - type = "function" - }, - pop = { - args = "()", - description = "Retrieves the value of a Channel message and removes it from the message queue.\n\nThe value of the message can be a boolean, string, number, LÖVE userdata, or a simple flat table. It returns nil if there are no messages in the queue.", - returns = "(value: value)", - type = "function" - }, - push = { - args = "(value: value)", - description = "Send a message to the thread Channel.\n\nThe value of the message can be a boolean, string, number, LÖVE userdata, or a simple flat table. Foreign userdata (Lua's files, LuaSocket, ENet, ...), functions, and tables inside tables are not supported.", - returns = "()", - type = "function" - }, - supply = { - args = "(value: value)", - description = "Send a message to the thread Channel and wait for a thread to accept it.\n\nThe value of the message can be a boolean, string, number, LÖVE userdata, or a simple flat table. Foreign userdata (Lua's files, LuaSocket, ENet, ...), functions, and tables inside tables are not supported.", - returns = "()", - type = "function" - } - }, - description = "A channel is a way to send and receive data to and from different threads.", - type = "lib" - }, - Thread = { - childs = { - isRunning = { - args = "()", - description = "Returns whether the thread is currently running.\n\nThreads which are not running can be (re)started with Thread:start.", - returns = "()", - type = "function" - }, - start = { - args = "(arg1: value, arg2: value, ...: value)", - description = "Starts the thread.\n\nThreads can be restarted after they have completed their execution.", - returns = "()", - type = "function" - }, - wait = { - args = "()", - description = "Wait for a thread to finish. This call will block until the thread finishes.", - returns = "()", - type = "function" - } - }, - description = "A Thread is a chunk of code that can run in parallel with other threads.\n\nThreads will place all Lua errors in \"error\". To retrieve the error, call Thread:get('error') in the main thread.", - type = "lib" - }, - newChannel = { - args = "()", - description = "Create a new unnamed thread channel.\n\nOne use for them is to pass new unnamed channels to other threads via Channel:push", - returns = "(channel: Channel)", - type = "function" - }, - newThread = { - args = "(filename: string)", - description = "Creates a new Thread from a File or Data object.", - returns = "(thread: Thread)", - type = "function" - } - }, - description = "Allows you to work with threads.\n\nThreads are separate Lua environments, running in parallel to the main code. As their code runs separately, they can be used to compute complex operations without adversely affecting the frame rate of the main thread. However, as they are separate environments, they cannot access the variables and functions of the main thread, and communication between threads is limited.\n\nAll LOVE objects (userdata) are shared among threads so you'll only have to send their references across threads. You may run into concurrency issues if you manipulate an object on multiple threads at the same time.\n\nWhen a Thread is started, it only loads the love.thread module. Every other module has to be loaded with require.", - type = "class" - }, - threaderror = { - args = "(thread: Thread, errorstr: string)", - description = "Callback function triggered when a Thread encounters an error.", - returns = "()", - type = "function" - }, - timer = { - childs = { - getDelta = { - args = "()", - description = "Returns the time between the last two frames.", - returns = "(dt: number)", - type = "function" - }, - getFPS = { - args = "()", - description = "Returns the current frames per second.", - returns = "(fps: number)", - type = "function" - }, - getTime = { - args = "()", - description = "Returns the value of a timer with an unspecified starting time. This function should only be used to calculate differences between points in time, as the starting time of the timer is unknown.", - returns = "(time: number)", - type = "function" - }, - sleep = { - args = "(s: number)", - description = "Sleeps the program for the specified amount of time.", - returns = "()", - type = "function" - }, - step = { - args = "()", - description = "Measures the time between two frames. Calling this changes the return value of love.timer.getDelta.", - returns = "()", - type = "function" - } - }, - description = "Provides an interface to the user's clock.", - type = "lib" - }, - touch = { - childs = { - getPressure = { - args = "(id: light userdata)", - description = "Gets the current pressure of the specified touch-press.", - returns = "(pressure: number)", - type = "function" - }, - getTouches = { - args = "()", - description = "Gets a list of all active touch-presses.", - returns = "(touches: table)", - type = "function" - } - }, - description = "Provides an interface to touch-screen presses.", - type = "lib" - }, - touchmoved = { - args = "(id: light userdata, x: number, y: number, pressure: number)", - description = "Callback function triggered when a touch press moves inside the touch screen.", - returns = "()", - type = "function" - }, - touchpressed = { - args = "(id: light userdata, x: number, y: number, pressure: number)", - description = "Callback function triggered when the touch screen is touched.", - returns = "()", - type = "function" - }, - touchreleased = { - args = "(id: light userdata, x: number, y: number, pressure: number)", - description = "Callback function triggered when the touch screen stops being touched.", - returns = "()", - type = "function" - }, - update = { - args = "(dt: number)", - description = "Callback function triggered when a key is pressed.", - returns = "()", - type = "function" - }, - video = { - childs = { - Video = { - childs = { - getFilter = { - args = "()", - description = "Gets the scaling filters used when drawing the Video.", - returns = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - type = "function" - }, - getHeight = { - args = "()", - description = "Gets the height of the Video in pixels.", - returns = "(height: number)", - type = "function" - }, - getSource = { - args = "()", - description = "Gets the audio Source used for playing back the video's audio. May return nil if the video has no audio, or if Video:setSource is called with a nil argument.", - returns = "(source: Source)", - type = "function" - }, - getStream = { - args = "()", - description = "Gets the VideoStream object used for decoding and controlling the video.", - returns = "(stream: VideoStream)", - type = "function" - }, - getWidth = { - args = "()", - description = "Gets the width of the Video in pixels.", - returns = "(width: number)", - type = "function" - }, - isPlaying = { - args = "()", - description = "Gets whether the Video is currently playing.", - returns = "(playing: boolean)", - type = "function" - }, - pause = { - args = "()", - description = "Pauses the Video.", - returns = "()", - type = "function" - }, - play = { - args = "()", - description = "Starts playing the Video. In order for the video to appear onscreen it must be drawn with love.graphics.draw.", - returns = "()", - type = "function" - }, - rewind = { - args = "()", - description = "Rewinds the Video to the beginning.", - returns = "()", - type = "function" - }, - seek = { - args = "(offset: number)", - description = "Sets the current playback position of the Video.", - returns = "()", - type = "function" - }, - setFilter = { - args = "(min: FilterMode, mag: FilterMode, anisotropy: number)", - description = "Sets the scaling filters used when drawing the Video.", - returns = "()", - type = "function" - }, - setSource = { - args = "(source: Source)", - description = "Sets the audio Source used for playing back the video's audio. The audio Source also controls playback speed and synchronization.", - returns = "()", - type = "function" - }, - tell = { - args = "(seconds: number)", - description = "Gets the current playback position of the Video.", - returns = "()", - type = "function" - } - }, - description = "A drawable video.", - type = "lib" - }, - newVideoStream = { - args = "(filename: string)", - description = "Creates a new VideoStream. Currently only Ogg Theora video files are supported. VideoStreams can't draw videos, see love.graphics.newVideo for that.", - returns = "(videostream: VideoStream)", - type = "function" - } - }, - description = "This module is responsible for decoding, controlling, and streaming video files.\n\nIt can't draw the videos, see love.graphics.newVideo and Video objects for that.", - type = "class" - }, - visible = { - args = "(v: boolean)", - description = "Callback function triggered when window is minimized/hidden or unminimized by the user.", - returns = "()", - type = "function" - }, - wheelmoved = { - args = "(x: number, y: number)", - description = "Callback function triggered when the mouse wheel is moved.", - returns = "()", - type = "function" - }, - window = { - childs = { - FullscreenType = { - childs = { - desktop = { - description = "Sometimes known as borderless fullscreen windowed mode. A borderless screen-sized window is created which sits on top of all desktop UI elements. The window is automatically resized to match the dimensions of the desktop, and its size cannot be changed.", - type = "value" - }, - exclusive = { - description = "Standard exclusive-fullscreen mode. Changes the display mode (actual resolution) of the monitor.", - type = "value" - } - }, - description = "class constants", - type = "class" - }, - fromPixels = { - args = "(pixelvalue: number)", - description = "Converts a number from pixels to density-independent units.\n\nThe pixel density inside the window might be greater (or smaller) than the \"size\" of the window. For example on a retina screen in Mac OS X with the highdpi window flag enabled, the window may take up the same physical size as an 800x600 window, but the area inside the window uses 1600x1200 pixels. love.window.fromPixels(1600) would return 800 in that case.\n\nThis function converts coordinates from pixels to the size users are expecting them to display at onscreen. love.window.toPixels does the opposite. The highdpi window flag must be enabled to use the full pixel density of a Retina screen on Mac OS X and iOS. The flag currently does nothing on Windows and Linux, and on Android it is effectively always enabled.\n\nMost LÖVE functions return values and expect arguments in terms of pixels rather than density-independent units.", - returns = "(value: number)", - type = "function" - }, - getDisplayName = { - args = "(displayindex: number)", - description = "Gets the name of a display.", - returns = "(name: string)", - type = "function" - }, - getFullscreen = { - args = "()", - description = "Gets whether the window is fullscreen.", - returns = "(fullscreen: boolean, fstype: FullscreenType)", - type = "function" - }, - getFullscreenModes = { - args = "(display: number)", - description = "Gets a list of supported fullscreen modes.", - returns = "(modes: table)", - type = "function" - }, - getIcon = { - args = "()", - description = "Gets the window icon.", - returns = "(imagedata: ImageData)", - type = "function" - }, - getMode = { - args = "()", - description = "Returns the current display mode.", - returns = "(width: number, height: number, flags: table)", - type = "function" - }, - getPixelScale = { - args = "()", - description = "Gets the DPI scale factor associated with the window.\n\nThe pixel density inside the window might be greater (or smaller) than the \"size\" of the window. For example on a retina screen in Mac OS X with the highdpi window flag enabled, the window may take up the same physical size as an 800x600 window, but the area inside the window uses 1600x1200 pixels. love.window.getPixelScale() would return 2.0 in that case.\n\nThe love.window.fromPixels and love.window.toPixels functions can also be used to convert between units.\n\nThe highdpi window flag must be enabled to use the full pixel density of a Retina screen on Mac OS X and iOS. The flag currently does nothing on Windows and Linux, and on Android it is effectively always enabled.", - returns = "(scale: number)", - type = "function" - }, - getPosition = { - args = "()", - description = "Gets the position of the window on the screen.\n\nThe window position is in the coordinate space of the display it is currently in.", - returns = "(x: number, y: number, display: number)", - type = "function" - }, - getTitle = { - args = "()", - description = "Gets the window title.", - returns = "(title: string)", - type = "function" - }, - hasFocus = { - args = "()", - description = "Checks if the game window has keyboard focus.", - returns = "(focus: boolean)", - type = "function" - }, - hasMouseFocus = { - args = "()", - description = "Checks if the game window has mouse focus.", - returns = "(focus: boolean)", - type = "function" - }, - isCreated = { - args = "()", - description = "Checks if the window has been created.", - returns = "(created: boolean)", - type = "function" - }, - isDisplaySleepEnabled = { - args = "()", - description = "Gets whether the display is allowed to sleep while the program is running.\n\nDisplay sleep is disabled by default. Some types of input (e.g. joystick button presses) might not prevent the display from sleeping, if display sleep is allowed.", - returns = "(enabled: boolean)", - type = "function" - }, - isVisible = { - args = "()", - description = "Checks if the game window is visible.\n\nThe window is considered visible if it's not minimized and the program isn't hidden.", - returns = "(visible: boolean)", - type = "function" - }, - maximize = { - args = "()", - description = "Makes the window as large as possible.\n\nThis function has no effect if the window isn't resizable, since it essentially programmatically presses the window's \"maximize\" button.", - returns = "()", - type = "function" - }, - minimize = { - args = "()", - description = "Minimizes the window to the system's task bar / dock.", - returns = "()", - type = "function" - }, - requestAttention = { - args = "(continuous: boolean)", - description = "Causes the window to request the attention of the user if it is not in the foreground.\n\nIn Windows the taskbar icon will flash, and in OS X the dock icon will bounce.", - returns = "()", - type = "function" - }, - setDisplaySleepEnabled = { - args = "(enable: boolean)", - description = "Sets whether the display is allowed to sleep while the program is running.\n\nDisplay sleep is disabled by default. Some types of input (e.g. joystick button presses) might not prevent the display from sleeping, if display sleep is allowed.", - returns = "()", - type = "function" - }, - setFullscreen = { - args = "(fullscreen: boolean)", - description = "Enters or exits fullscreen. The display to use when entering fullscreen is chosen based on which display the window is currently in, if multiple monitors are connected.\n\nIf fullscreen mode is entered and the window size doesn't match one of the monitor's display modes (in normal fullscreen mode) or the window size doesn't match the desktop size (in 'desktop' fullscreen mode), the window will be resized appropriately. The window will revert back to its original size again when fullscreen mode is exited using this function.", - returns = "(success: boolean)", - type = "function" - }, - setIcon = { - args = "(imagedata: ImageData)", - description = "Sets the window icon until the game is quit. Not all operating systems support very large icon images.", - returns = "(success: boolean)", - type = "function" - }, - setMode = { - args = "(width: number, height: number, flags: table)", - description = "Sets the display mode and properties of the window.\n\nIf width or height is 0, setMode will use the width and height of the desktop.\n\nChanging the display mode may have side effects: for example, canvases will be cleared and values sent to shaders with Shader:send will be erased. Make sure to save the contents of canvases beforehand or re-draw to them afterward if you need to.", - returns = "(success: boolean)", - type = "function" - }, - setPosition = { - args = "(x: number, y: number, display: number)", - description = "Sets the position of the window on the screen.\n\nThe window position is in the coordinate space of the specified display.", - returns = "()", - type = "function" - }, - setTitle = { - args = "(title: string)", - description = "Sets the window title.", - returns = "()", - type = "function" - }, - showMessageBox = { - args = "(title: string, message: string, type: MessageBoxType, attachtowindow: boolean)", - description = "Displays a message box dialog above the love window. The message box contains a title, optional text, and buttons.", - returns = "(success: boolean)", - type = "function" - }, - toPixels = { - args = "(value: number)", - description = "Converts a number from density-independent units to pixels.\n\nThe pixel density inside the window might be greater (or smaller) than the \"size\" of the window. For example on a retina screen in Mac OS X with the highdpi window flag enabled, the window may take up the same physical size as an 800x600 window, but the area inside the window uses 1600x1200 pixels. love.window.toPixels(800) would return 1600 in that case.\n\nThis is used to convert coordinates from the size users are expecting them to display at onscreen to pixels. love.window.fromPixels does the opposite. The highdpi window flag must be enabled to use the full pixel density of a Retina screen on Mac OS X and iOS. The flag currently does nothing on Windows and Linux, and on Android it is effectively always enabled.\n\nMost LÖVE functions return values and expect arguments in terms of pixels rather than density-independent units.", - returns = "(pixelvalue: number)", - type = "function" - } - }, - description = "Provides an interface for modifying and retrieving information about the program's window.", - type = "lib" - } - }, - description = "Love2d modules, functions, and callbacks.", - type = "lib" -} - -do return {love = love} end - --- the following code is used to convert love_api.lua to a proper format -love = dofile('love_api.lua') - --- conversion script -local function convert(l) - local function merge(...) -- merges tables into one table - local r = {} - for _,v in pairs({...}) do - for _,e in pairs(v) do table.insert(r, e) end - end - return r - end - local function params(t) -- merges parameters and return results - if not t then return end - local r = {} - for _,v in ipairs(t) do - table.insert(r, v.name .. ': ' .. v.type) - end - return '(' .. table.concat(r, ", ") .. ')' - end - - if l.modules then - l.description = 'Love2d modules, functions, and callbacks.' - l.type = "lib" - l.childs = merge(l.modules, l.functions or {}, l.callbacks or {}) - l.types = nil -- don't need types - l.callbacks = nil - l.functions = nil - l.modules = nil - end - - if not l.childs then return end - - for n,v in ipairs(l.childs) do - if v.functions and #v.functions > 1 and #v.functions[1] == 0 then - io.stderr:write("Alternative signature ignored for "..v.name..".\n") - table.remove(v.functions, 1) - end - v.childs = merge(v.types, v.functions, v.constants, v.enums) - if v.name then - l.childs[v.name] = v - v.name = nil - end - if #v.childs > 0 and v.childs[1] then - if v.childs[1].returns then v.returns = params(v.childs[1].returns) end - if v.childs[1].arguments then v.args = params(v.childs[1].arguments) end - end - -- some nodes have first chils as empty and the data is in the second one (Mouse.setCursor) - if v.variants and #v.variants > 0 then - v.returns = params(v.variants[1] and v.variants[1].returns or v.variants[2] and v.variants[2].returns) - end - if v.variants and #v.variants > 0 then - v.args = params(v.variants[1] and v.variants[1].arguments or v.variants[2] and v.variants[2].arguments) - end - local nochildren = #v.childs == 0 or v.returns or v.args - v.type = nochildren and ((v.returns or v.args or v.variants) and "function" or "value") - or v.types and "class" - or v.constants and "class" - or v.functions and "lib" - or "function" - if v.constants then v.description = "class constants" end - v.variants = nil - v.types = nil - v.functions = nil - v.constants = nil - v.enums = nil - v.supertypes = nil - v.constructors = nil - if nochildren then v.childs = nil end - if v.type == "function" then - v.args = v.args or '()' - v.returns = v.returns or '()' - end - l.childs[n] = nil - convert(v) - end - return l -end - -package.path = package.path .. ';../../lualibs/?/?.lua;../../lualibs/?.lua' -package.cpath = package.cpath .. ';../../bin/clibs/?.dll' -print((require 'mobdebug').line(convert(love), {indent = ' ', comment = false})) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/luajit2.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/luajit2.lua deleted file mode 100644 index 07d9074..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/luajit2.lua +++ /dev/null @@ -1,52 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - --- function helpers - -local function fn (description) - local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())") - if not description2 then - return {type="function",description=description, - returns="(?)"} - end - returns = returns:gsub("^%s+",""):gsub("%s+$","") - local ret = returns:sub(2,-2) - local vt = ret:match("^%[?string") and "string" - vt = vt or ret:match("^%[?table") and "table" - vt = vt or ret:match("^%[?file") and "io" - return {type="function",description=description2, - returns=returns, args = args, valuetype = vt} -end - -local function val (description) - return {type="value",description = description} -end - ---------------------------- - -local api = { -ffi = { - description = "FFI", - type = "lib", - childs = { - cdef = fn "Adds multiple C declarations for types or external symbols - ()(string)", - load = fn "This loads the dynamic library given by name and returns a new C library namespace which binds to its symbols. On POSIX systems, if global is true, the library symbols are loaded into the global namespace, too. - (userdata)(string,[global])", - new = fn "The following API functions create cdata objects (type() returns 'cdata'). All created cdata objects are garbage collected. - (cdata)(string/ctype,nelement,init...)", - typeof = fn "Creates a ctype object for the given ct. - (ctype)(ct)", - cast = fn "Creates a scalar cdata object for the given ct. The cdata object is initialized with init according to C casting rules. - (cdata)(ctype,cdata init)", - metatype = fn "Creates a ctype object for the given ct and associates it with a metatable. Only struct/union types, complex numbers and vectors are allowed. Other types may be wrapped in a struct, if needed. - (cdata)(ct,table meta)", - gc = fn "Associates a finalizer with a pointer or aggregate cdata object. The cdata object is returned unchanged. - (cdata)(ct,function finalizer)", - sizeof = fn "Returns the size of ct in bytes. Returns nil if the size is not known. - (number)(ct,[nelem])", - alignof = fn "Returns the minimum required alignment for ct in bytes. - (number)(ct)", - offsetof = fn "Returns the offset (in bytes) of field relative to the start of ct, which must be a struct. Additionally returns the position and the field size (in bits) for bit fields. - (number)(ct, field)", - istype = fn "Returns true if obj has the C type given by ct. Returns false otherwise. - (boolean)(ct,obj)", - string = fn "Creates an interned Lua string from the data pointed to by ptr. If the optional argument len is missing, ptr is converted to a 'char *' and the data is assumed to be zero-terminated. The length of the string is computed with strlen(). - (string)(ptr, [number len])", - copy = fn "Copies the data pointed to by src to dst. dst is converted to a 'void *' and src is converted to a 'const void *'. - ()(dst,[src,len] / [string])", - fill = fn "Fills the data pointed to by dst with len constant bytes, given by c. If c is omitted, the data is zero-filled. - ()(dst, len, [c])", - abi = fn "Returns true if param (a Lua string) applies for the target ABI (Application Binary Interface). Returns false otherwise. 32bit 64bit lq be fpu softfp hardfp eabi win. - (boolean)(string)", - os = val "string value of OS", - } -}, -} - -return api \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/wxwidgets.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/wxwidgets.lua deleted file mode 100644 index 6882928..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/lua/wxwidgets.lua +++ /dev/null @@ -1,24 +0,0 @@ -local function populateAPI(t) - local api = {} - for k,v in pairs(t) do - api[k] = { - type = (type(v) == "function" and "function" or "value"), - description = "", - returns = "", - } - end - return api -end - -return { - wx = { - type = "lib", - description = "wx lib", - childs = populateAPI(wx), - }, - wxstc = { - type = "lib", - description = "wxSTC lib", - childs = populateAPI(wxstc), - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/opencl/std.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/opencl/std.lua deleted file mode 100644 index 675d945..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/api/opencl/std.lua +++ /dev/null @@ -1,278 +0,0 @@ -local funcstring = -[[ -get_work_dim() Returns the number of dimensions in use -get_global_size(uint dimindx) Returns the number of global work-items specified for dimension identified by dimindx -get_global_id(uint dimindx) Returns the unique global work-item ID value for dimension identified by dimindx -get_local_size(uint dimindx) Returns the number of local work-items specified in dimension identified by dimindx -get_local_id(uint dimindx) Returns the unique local work-item ID i.e. a work-item within a specific work-group for dimension identified by dimindx. -get_num_groups(uint dimindx) Returns the number of work-groups that will execute a kernel for dimension identified by dimindx -get_group_id(uint dimindx) Returns the work-group ID -acos(gentype) Arc cosine function -acosh(gentype) Inverse hyperbolic cosine -acospi(gentype) Compute acos (x) / PI -asin(gentype) Arc sine function -asinh(gentype) Inverse hyperbolic sine -asinpi(gentype x) Compute asin (x) / PI -atan(gentype y_over_x) Arc tangent function -atan2(gentype y, gentype x) Arc tangent of y / x -atanh(gentype) Hyperbolic arc tangent. -atanpi(gentype x) Compute atan (x) / PI -atan2pi(gentype y, gentype x) Compute atan2 (y, x) / PI -cbrt(gentype) Compute cube-root -ceil(gentype) Round to integral value using the round to +ve infinity rounding mode -copysign(gentype x, gentype y) Returns x with its sign changed to match the sign of y -cos(gentype) Compute cosine -cosh(gentype) Compute hyperbolic consine -cospi(gentype x) Compute cos (PI*x) -erfc(gentype) Complementary error function -erf(gentype) Error function encountered in integrating the normal distribution -exp(gentype x) Compute the base- e exponential of x -exp2(gentype) Exponential base 2 function -exp10(gentype) Exponential base 10 function -expm1(gentype x) Compute e^x - 1.0 -fabs(gentype) Compute absolute value of a floating-point number -fdim(gentype x, gentype y) x - y if x > y, +0 if x is less than or equal to y -floor(gentype) Round to integral value using the round to –ve infinity rounding mode -fma(gentype a, gentype b, gentype c) Returns the correctly rounded floating-point representation of the sum of c with the infinitely precise product of a and b -fmax(gentype x, gentype y) Returns y if x < y, otherwise it returns x -fmin(gentype x, gentype y) Returns y if y < x, otherwise it returns x -fmod(gentype x, gentype y) Modulus. Returns x – y * trunc (x/y) -fract(gentype x, gentype *iptr) Returns fmin( x – floor (x), 0x1.fffffep-1f ). -frexp(gentype x, intn *exp) Extract mantissa and exponent from x -hypot(gentype x, gentype y) Compute the value of the square root of x2+y2 -ilogb(gentype x) Return the exponent as an integer value -ldexp(gentype x, intn n) Multiply x by 2 to the power n -lgamma(gentype x) Returns the natural logarithm of the absolute value of the gamma function -lgamma_r(gentype x, intn *signp) Returns the natural logarithm of the absolute value of the gamma function -log(gentype) Compute natural logarithm -log2(gentype) Compute a base 2 logarithm -log10(gentype) Compute a base 10 logarithm -log1p(gentype x) Compute loge(1.0 + x) -logb(gentype x) Compute the exponent of x, which is the integral part of logr|x| -mad(gentype a, gentype b, gentype c) Approximates a * b + c. -modf(gentype x, gentype *iptr) Decompose a floating-point number -nan(uintn nancode) Returns a quiet NaN -nextafter(gentype x, gentype y) Computes the next representable single-precision floating-point value following x in the direction of y. -pow(gentype x, gentype y) Compute x to the power y -pown(gentype x, intn y) Compute x to the power y, where y is an integer -powr(gentype x, gentype y) Compute x to the power y, where x is >= 0 -remainder(gentype x, gentype y) r = x - n*y, where n is the integer nearest the exact value of x/y -remquo(gentype x, gentype y, intn *quo) r = x - n*y, where n is the integer nearest the exact value of x/y -rint(gentype) Round to integral value (using round to nearest even rounding mode) -rootn(gentype x, intn y) Compute x to the power 1/y -round(gentype x) Return the integral value nearest to x rounding halfway cases away from zero -rsqrt(gentype) Compute inverse square root -sin(gentype) Compute sine -sincos(gentype x, gentype *cosval) Compute sine and cosine of x -sinh(gentype) Compute hyperbolic sine. -sinpi(gentype x) Compute sin (PI*x) -sqrt(gentype) Compute square root -tan(gentype) Compute tangent -tanh(gentype) Compute hyperbolic tangent -tanpi(gentype x) Compute tan (PI*x) -tgamma(gentype) Compute the gamma function -trunc(gentype) Round to integral value using the round to zero -abs(gentype x) Returns |x| -abs_diff(gentype x, gentype y) Returns |x – y| without modulo overflow -add_sat(gentype x, gentype y) Returns x + y and saturates the result -hadd(gentype x, gentype y) Returns (x + y) >> 1 -rhadd(gentype x, gentype y) Returns (x + y + 1) >> 1 -clz(gentype x) Returns the number of leading 0-bits in x, starting at the most significant bit position. -mad_hi(gentype a, gentype b, gentype c) Returns mul_hi(a, b) + c -mad_sat(gentype a, gentype b, gentype c) Returns a * b + c and saturates the result -max(gentype x, gentype y) Returns y if x < y, otherwise it returns x -min(gentype x, gentype y) Returns y if y < x, otherwise it returns x -mul_hi(gentype x, gentype y) Computes x * y and returns the high half of the product of x and y -rotate(gentype v, gentype i) -sub_sat(gentype x, gentype y) Returns x - y and saturates the result -upsample(charn hi, ucharn lo) result[i] = ((short)hi[i] << 8) | lo[i] -mad24(gentype x, gentype y, gentype z) -mul24(gentype x, gentype y) -clamp(gentype x, gentype minval, gentype maxval) Returns fmin(fmax(x, minval), maxval) -degrees(gentype radians) Converts radians to degrees -max(gentype x, gentype y) -min(gentype x, gentype y) -mix(gentype x, gentype y, gentype a) Returns the linear blend of x&y: x + (y – x) * a -radians(gentype degrees) Converts degrees to radians -step(gentype edge, gentype x) Returns 0.0 if x < edge, otherwise it returns 1.0 -smoothstep(genType edge0, genType edge1, genType x) -sign(gentype x) -cross(float4 p0, float4 p1) Returns the cross product of p0.xyz and p1.xyz. -dot(gentype p0, gentype p1) Compute dot product -distance(gentype p0, gentype p1) Returns the distance between p0 and p1 -length(gentype p) Return the length of vecto -normalize(gentype p) Returns a vector in the same direction as p but with length of 1. -fast_distance(gentype p0, gentype p1) Returns fast_length(p0 – p1). -fast_length(gentype p) Returns the length of vector -fast_normalize(gentype p) Returns a vector in the same direction as p but with length of 1. -read_imagef(image2d_t image, sampler_t sampler, int2 coord) -read_imagei(image2d_t image, sampler_t sampler, int2 coord) -read_imageui(image2d_t image, sampler_t sampler, int2 coord) -write_imagef(image2d_t image, int2 coord, float4 color) -write_imagei(image2d_t image, int2 coord, int4 color) -write_imageui(image2d_t image, int2 coord, unsigned int4 color) -get_image_width(image2d_t image) -get_image_width(image3d_t image) -get_image_height(image2d_t image) -get_image_height(image3d_t image) -get_image_channel_data_type(image2d_t image) -get_image_channel_data_type(image3d_t image) -get_image_channel_order(image2d_t image) -get_image_channel_order(image3d_t image) -get_image_dim(image2d_t image) -get_image_dim(image3d_t image) -barrier(cl_mem_fence_flags flags) All work-items in a work-group executing the kernel must execute this function before any are allowed to continue execution beyond the barrier. -mem_fence(cl_mem_fence_flags flags) Orders loads and stores of a work-item executing a kernel. -read_mem_fence(cl_mem_fence_flags flags) Read memory barrier that orders only loads. -write_mem_fence(cl_mem_fence_flags flags) Write memory barrier that orders only stores. -async_work_group_copy(gentype *dst, const gentype *src, size_t num_elements, event_t event) Perform an async copy of num_elements gentype elements from src to dst. -wait_group_events(int num_events, event_t *event_list) Wait for events that identify the async_work_group_copy operations to complete. -prefetch(const __global gentype *p, size_t num_elements) Prefetch num_elements * sizeof(gentype) bytes into the global cache. -vload2(size_t offset, const type *p) Read vector data from memory -vload4(size_t offset, const type *p) Read vector data from memory -vload8(size_t offset, const type *p) Read vector data from memory -vload16(size_t offset, const type *p) Read vector data from memory -vstore2(type2 data, size_t offset, type *p) Write vector data to memory -vstore4(type4 data, size_t offset, type *p) Write vector data to memory -vstore8(type8 data, size_t offset, type *p) Write vector data to memory -vstore16(type16 data, size_t offset, type *p) Write vector data to memory -]] - -local function fn (description) - local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())") - if not description2 then - return {type="function",description=description, - returns="(?)"} - end - return {type="function",description=description2, - returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args} -end - -local function val (description) - return {type="value",description = description} -end --- docs -local api = { -} - - -local convtypes = [[bool char uchar short ushort int uint long ulong float double]] -local convout = {} -for i in convtypes:gmatch("([%w_]+)") do - local suffix = {"","_rte","_rtz","_rtp","_rtn"} - for k,t in ipairs(suffix) do - table.insert(convout,"convert_"..i..t) - table.insert(convout,"convert_"..i.."_sat"..t) - local vectors = {2,4,8,16} - for n,v in ipairs(vectors) do - table.insert(convout,"convert_"..i..v..t) - table.insert(convout,"convert_"..i..v.."_sat"..t) - end - end -end -convout = table.concat(convout, " ") - -local astypes = [[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t - long ulong char short unsigned - float2 float4 float8 float16 - double2 double4 double8 double16 - char2 char4 char8 char16 - uchar2 uchar4 uchar8 uchar16 - short2 short4 short8 short16 - ushort2 ushort4 ushort8 ushort16 - int2 int4 int8 int16 - uint2 uint4 uint8 uint16 - long2 long4 long8 long16 - ulong2 ulong4 ulong8 ulong16]] - -local astypeout = {} -for i in astypes:gmatch("([%w_]+)") do - table.insert(astypeout, "as_"..i) -end -astypeout = table.concat(astypeout, " ") - -local keyw = astypeout.." "..convout.." "..[[ - int uint uchar ushort half float bool double size_t ptrdiff_t intptr_t uintptr_t void - long ulong char short unsigned - half2 half4 half8 half16 - float2 float4 float8 float16 - double2 double4 double8 double16 - char2 char4 char8 char16 - uchar2 uchar4 uchar8 uchar16 - short2 short4 short8 short16 - ushort2 ushort4 ushort8 ushort16 - int2 int4 int8 int16 - uint2 uint4 uint8 uint16 - long2 long4 long8 long16 - ulong2 ulong4 ulong8 ulong16 - image2d_t image3d_t sampler_t event_t cl_image_format - - struct typedef void const - return switch case for do while if else break continue volatile - CLK_A CLK_R CLK_RG CLK_RGB CLK_RGBA CLK_ARGB CLK_BGRA CLK_INTENSITY CLK_LUMINANCE - - MAXFLOAT HUGE_VALF INFINITY NAN - CLK_LOCAL_MEM_FENCE CLK_GLOBAL_MEM_FENCE - CLK_SNORM_INT8 - CLK_SNORM_INT16 - CLK_UNORM_INT8 - CLK_UNORM_INT16 - CLK_UNORM_SHORT_565 - CLK_UNORM_SHORT_555 - CLK_UNORM_SHORT_101010 - CLK_SIGNED_INT8 - CLK_SIGNED_INT16 - CLK_SIGNED_INT32 - CLK_UNSIGNED_INT8 - CLK_UNSIGNED_INT16 - CLK_UNSIGNED_INT32 - CLK_HALF_FLOAT - CLK_FLOAT - __FILE__ __LINE__ __OPENCL_VERSION__ __ENDIAN_LITTLE__ - __ROUNDING_MODE__ __IMAGE_SUPPORT__ __FAST_RELAXED_MATH__ - - __kernel kernel __attribute__ __read_only __write_only read_only write_only - __constant constant __local local __global global __private private - vec_type_hint work_group_size_hint reqd_work_group_size - aligned packed endian host device - - async_work_group_copy wait_group_events prefetch - clamp min max degrees radians sign smoothstep step mix - mem_fence read_mem_fence write_mem_fence - cross prod distance dot length normalize fast_distance fast_length fast_normalize - read_image write_image get_image_width get_image_height get_image_depth - get_image_channel_data_type get_image_channel_order - get_image_dim - abs abs_diff add_sat clz hadd mad24 mad_hi mad_sat - mul24 mul_hi rhadd rotate sub_sat upsample - read_imagei write_imagei read_imageui write_imageui - read_imagef write_imagef - - isequal isnotequal isgreater isgreaterequal isless islessequal islessgreater - isfinite isinf isnan isnormal isordered isunordered signbit any all bitselect select - - acos acosh acospi asin asinh asinpi atan atan2 atanh atanpi atan2pi - cbrt ceil copysign cos half_cos native_cos cosh cospi half_divide native_divide - erf erfc exp half_exp native_exp exp2 half_exp2 native_exp2 exp10 half_exp10 native_exp10 - expm1 fabs fdim floor fma fmax fmin fmod fract frexp hypot ilogb - ldexp lgamma lgamma_r log half_log native_log log2 half_log2 native_log2 - log10 half_log10 native_log10 log1p logb mad modf nan nextafter - pow pown powr half_powr native_powr half_recip native_recip - remainder remquo rint round rootn rsqrt half_rsqrt native_rsqrt - sin half_sin native_sin sincos sinh sinpi sqrt half_sqrt native_sqrt - tan half_tan native_tan tanh tanpi tgamma trunc - - barrier - vload2 vload4 vload8 vload16 - vload_half vload_half2 vload_half4 vload_half8 vload_half16 vloada_half4 vloada_half8 vloada_half16 - vstore2 vstore4 vstore8 vstore16 - vstore_half vstore_half2 vstore_half4 vstore_half8 vstore_half16 vstorea_half4 vstorea_half8 vstorea_half16 - get_global_id get_global_size get_group_id get_local_id get_local_size get_num_groups get_work_dim -]] - --- keywords - shouldn't be left out -for w in keyw:gmatch("([a-zA-Z_0-9]+)") do - api[w] = {type="keyword"} -end - -return api \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/git/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/git/core.dylib deleted file mode 100644 index bbf0070..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/git/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/lfs.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/lfs.dylib deleted file mode 100644 index f7dec2f..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/lfs.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/mime/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/mime/core.dylib deleted file mode 100644 index 0ea96a2..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/mime/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/socket/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/socket/core.dylib deleted file mode 100644 index 0ecff6e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs/socket/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/mime/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/mime/core.dylib deleted file mode 100644 index 00b2ba9..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/mime/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/socket/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/socket/core.dylib deleted file mode 100644 index 301f903..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs52/socket/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/mime/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/mime/core.dylib deleted file mode 100644 index dd5dfa9..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/mime/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/socket/core.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/socket/core.dylib deleted file mode 100644 index 7700034..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/clibs53/socket/core.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua.dylib deleted file mode 100644 index 67fc36e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua52.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua52.dylib deleted file mode 100644 index 0f17292..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua52.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua53.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua53.dylib deleted file mode 100644 index 23c99d0..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/liblua53.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/libwx.dylib b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/libwx.dylib deleted file mode 100644 index bbc009c..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/libwx.dylib and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua deleted file mode 100755 index 4ae018e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/Info.plist b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/Info.plist deleted file mode 100644 index 6e2a3f2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/Info.plist +++ /dev/null @@ -1,38 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - lua - CFBundleDisplayName - Lua - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - org.Lua.LuaInterpreter - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - - CFBundleName - Lua - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - - CSResourcesFileMapped - - LSRequiresCarbon - - NSHumanReadableCopyright - - - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua deleted file mode 100755 index 4ae018e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua52 b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua52 deleted file mode 100755 index 032a6cf..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua52 and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua53 b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua53 deleted file mode 100755 index a372269..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua53 and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua52 b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua52 deleted file mode 100755 index 032a6cf..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua52 and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua53 b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua53 deleted file mode 100755 index a372269..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/bin/lua53 and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/.user.lua.un~ b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/.user.lua.un~ deleted file mode 100644 index f66eda1..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/.user.lua.un~ and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/estrela.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/estrela.lua deleted file mode 100644 index 102e1a8..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/estrela.lua +++ /dev/null @@ -1,19 +0,0 @@ --- If you have used Estrela for graphics shader authoring or luxinia, --- create/modify the `user.lua` file in the current folder --- and add `include "estrela"` (1.21+) to load all tools and specifications by default again. - --- load all tools, specs, and interpreters -local all = function() return true end -load.tools(all) -load.specs(all) -load.interpreters(all) - --- this flag means that toggling between projects, will not affect the --- list of opened files (old estrela default). -projectautoopen = false - --- default search paths for luxinia -local luxpath = os.getenv("LUXINIA") -path.luxinia = luxpath and luxpath.."/" or "../luxinia/engine/" -local luxpath2 = os.getenv("LUXINIA2") -path.luxinia2 = luxpath2 and luxpath2.."/" or "../luxinia2/runtime/bin_Windows_x86/" diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/de.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/de.lua deleted file mode 100644 index 0705078..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/de.lua +++ /dev/null @@ -1,345 +0,0 @@ -return { - [0] = function(c) return c == 1 and 1 or 2 end, -- plural - ["%s event failed: %s"] = "Ereignis fehlgeschlagen : %s", -- src\editor\package.lua - ["%s%% formatted..."] = nil, -- src\editor\print.lua - ["%s%% loaded..."] = "%s%% geladen...", -- src\editor\commands.lua - ["&About"] = "&Über", -- src\editor\menu_help.lua - ["&Add Watch"] = "&Beobachtungspunkt hinzufügen", -- src\editor\debugger.lua - ["&Break"] = "&Unterbrechung", -- src\editor\menu_project.lua - ["&Close Page"] = "S&eite schließen", -- src\editor\gui.lua, src\editor\menu_file.lua - ["&Community"] = "&Community", -- src\editor\menu_help.lua - ["&Compile"] = "&Compiler", -- src\editor\menu_project.lua - ["&Copy Value"] = "Wert kopieren", -- src\editor\debugger.lua - ["&Copy"] = "&Kopieren", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["&Default Layout"] = "Standard-&Layout", -- src\editor\menu_view.lua - ["&Delete Watch"] = "&Beobachtungspunkt entfernen", -- src\editor\debugger.lua - ["&Delete"] = "&Entfernen", -- src\editor\filetree.lua - ["&Documentation"] = "&Dokumentation", -- src\editor\menu_help.lua - ["&Edit Project Directory"] = "Projektverzeichnis ändern", -- src\editor\filetree.lua - ["&Edit Value"] = "Wert editieren", -- src\editor\debugger.lua - ["&Edit Watch"] = "&Beobachtungspunkt bearbeiten", -- src\editor\debugger.lua - ["&Edit"] = "&Bearbeiten", -- src\editor\menu_edit.lua - ["&File"] = "&Datei", -- src\editor\menu_file.lua - ["&Find"] = "&Finden", -- src\editor\menu_search.lua - ["&Fold/Unfold All"] = "A&lles ein-/ausklappen", -- src\editor\menu_edit.lua - ["&Frequently Asked Questions"] = "&FAQ", -- src\editor\menu_help.lua - ["&Getting Started Guide"] = "&Anfängerleitfaden", -- src\editor\menu_help.lua - ["&Help"] = "&Hilfe", -- src\editor\menu_help.lua - ["&New Directory"] = "&Neuer Ordner", -- src\editor\filetree.lua - ["&New"] = "&Neu", -- src\editor\menu_file.lua - ["&Open..."] = "&Öffnen...", -- src\editor\menu_file.lua - ["&Output/Console Window"] = "&Ausgabefenster/Konsole", -- src\editor\menu_view.lua - ["&Paste"] = "&Einfügen", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["&Print..."] = nil, -- src\editor\print.lua - ["&Project Page"] = "&Projektseite", -- src\editor\menu_help.lua - ["&Project"] = "&Projekt", -- src\editor\menu_project.lua - ["&Redo"] = "&Wiederholen", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["&Rename"] = "&Umbenennen", -- src\editor\filetree.lua - ["&Replace"] = "&Ersetzen", -- src\editor\menu_search.lua - ["&Run"] = "&Starten", -- src\editor\menu_project.lua - ["&Save"] = "&Speichern", -- src\editor\gui.lua, src\editor\menu_file.lua - ["&Search"] = "&Suchen", -- src\editor\menu_search.lua - ["&Select Command"] = nil, -- src\editor\gui.lua - ["&Sort"] = "&Sortieren", -- src\editor\menu_edit.lua - ["&Stack Window"] = "&Stapel/Stack", -- src\editor\menu_view.lua - ["&Start Debugger Server"] = "De&bugserver starten", -- src\editor\menu_project.lua - ["&Status Bar"] = "S&tatuszeile", -- src\editor\menu_view.lua - ["&Tool Bar"] = "&Werkzeugleiste", -- src\editor\menu_view.lua - ["&Tutorials"] = "&Tutorien", -- src\editor\menu_help.lua - ["&Undo"] = "&Rückgängig", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["&View"] = "&Ansicht", -- src\editor\menu_view.lua - ["&Watch Window"] = "&Beobachtungspunkte", -- src\editor\menu_view.lua - ["About %s"] = "Über %s", -- src\editor\menu_help.lua - ["Add To Scratchpad"] = "Zu Entwurf hinzufügen", -- src\editor\editor.lua - ["Add Watch Expression"] = "Beobachtungspunkt hinzufügen", -- src\editor\editor.lua - ["All files"] = "Alle Dateien", -- src\editor\commands.lua - ["Allow external process to start debugging"] = "Externem Prozeß erlauben, den Debugger zu starten", -- src\editor\menu_project.lua - ["Analyze the source code"] = "Quellcode analysieren", -- src\editor\inspect.lua - ["Analyze"] = "&Analyseroutine", -- src\editor\inspect.lua - ["Auto Complete Identifiers"] = "Auto-Vervollständigen von Bezeichnern", -- src\editor\menu_edit.lua - ["Auto complete while typing"] = "Auto-Vervollständigen beim Tippen", -- src\editor\menu_edit.lua - ["Binary file is shown as read-only as it is only partially loaded."] = "Binärdatei ist als schreibgeschützt angezeigt, da sie nur teilweise geladen wurde.", -- src\editor\commands.lua - ["Bookmark"] = "Lese&zeichen", -- src\editor\menu_edit.lua - ["Break execution at the next executed line of code"] = "Programmausführung bei der nächsten ausgeführten Zeile stoppen", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Breakpoint"] = nil, -- src\editor\menu_project.lua - ["C&lear Console Window"] = nil, -- src\editor\gui.lua - ["C&lear Output Window"] = "Ausgabefenster l&öschen", -- src\editor\gui.lua, src\editor\menu_project.lua - ["C&omment/Uncomment"] = "(Aus-)/K&ommentieren", -- src\editor\menu_edit.lua - ["Can't evaluate the expression while the application is running."] = "Kann den Ausdruck nicht auswerten solange die Anwendung läuft.", -- src\editor\debugger.lua - ["Can't open file '%s': %s"] = "Kann Datei '%s' nicht öffnen: %s", -- src\editor\findreplace.lua, src\editor\singleinstance.lua, src\editor\inspect.lua, src\editor\outline.lua - ["Can't process auto-recovery record; invalid format: %s."] = "Auto-Wiederherstellen nicht möglich; ungültiges Format: %s.", -- src\editor\commands.lua - ["Can't replace in read-only text."] = "Ersetzen in schreibgeschütztem Text nicht möglich.", -- src\editor\findreplace.lua - ["Can't run the entry point script ('%s')."] = "Kann Script für Einsprungspunkt ('%s') nicht ausführen.", -- src\editor\debugger.lua - ["Can't start debugger server at %s:%d: %s."] = "Kann Debugserver nicht starten (%s:%d): %s.", -- src\editor\debugger.lua - ["Can't start debugging for '%s'."] = "Kann Debuggen nicht starten für '%s'.", -- src\editor\debugger.lua - ["Can't start debugging session due to internal error '%s'."] = "Debugging kann nicht gestartet werden wegen internem Fehler '%s'.", -- src\editor\debugger.lua - ["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Debugging kann ohne geöffnete Datei nicht gestartet werden oder wenn die aktuelle Datei nicht gespeichert ist ('%s').", -- src\editor\debugger.lua - ["Can't stop debugger server as it is not started."] = "Kann Debugserver nicht stoppen wenn er vorher nicht gestartet wurde.", -- src\editor\debugger.lua - ["Cancelled by the user."] = "Durch Benutzer abgebrochen.", -- src\editor\findreplace.lua - ["Choose a directory to map"] = "Bitte Verzeichnis wählen zum virtuellen Einbinden", -- src\editor\filetree.lua - ["Choose a project directory"] = "Projektverzeichnis auswählen", -- src\editor\toolbar.lua, src\editor\menu_project.lua, src\editor\filetree.lua - ["Choose a search directory"] = "Bitte Verzeichnis zum Durchsuchen auswählen.", -- src\editor\findreplace.lua - ["Choose..."] = "Wählen...", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\filetree.lua - ["Clear Items"] = "Liste &löschen", -- src\editor\findreplace.lua, src\editor\menu_file.lua - ["Clear items from this list"] = "Diese Liste löschen", -- src\editor\menu_file.lua - ["Clear the output window before compiling or debugging"] = "Vor Kompilieren oder Debuggen das Ausgabefenster löschen", -- src\editor\menu_project.lua - ["Close &Other Pages"] = "A&ndere Seiten schließen", -- src\editor\gui.lua - ["Close A&ll Pages"] = "&Alle Seiten schließen", -- src\editor\gui.lua - ["Close the current editor window"] = "Aktuelles Editorfenster schließen", -- src\editor\menu_file.lua - ["Co&ntinue"] = "&Fortsetzen", -- src\editor\menu_project.lua - ["Col: %d"] = "Spalte: %d", -- src\editor\editor.lua - ["Command Line Parameters..."] = "Kommandozeilenparameter...", -- src\editor\menu_project.lua - ["Command line parameters"] = "Kommandozeilenparameter", -- src\editor\menu_project.lua - ["Comment or uncomment current or selected lines"] = "Ausgewählte bzw. aktive Zeile (un-)kommentieren", -- src\editor\menu_edit.lua - ["Compilation error"] = "Fehler beim Kompilieren", -- src\editor\commands.lua, src\editor\debugger.lua - ["Compilation successful; %.0f%% success rate (%d/%d)."] = "Kompilieren erfolgreich; Erfolgsquote von %.0f%% (%d/%d).", -- src\editor\commands.lua - ["Compile the current file"] = "Aktuelle Datei kompilieren", -- src\editor\menu_project.lua - ["Complete &Identifier"] = "&Bezeichner vervollständigen", -- src\editor\menu_edit.lua - ["Complete the current identifier"] = " Aktuellen Bezeichner vervollständigen", -- src\editor\menu_edit.lua - ["Consider removing backslash from escape sequence '%s'."] = "Möglicherweise muß `\' aus '%s' entfernt werden.", -- src\editor\commands.lua - ["Copy Full Path"] = "Kopiere Pfadangabe", -- src\editor\gui.lua, src\editor\filetree.lua - ["Copy selected text to clipboard"] = "Text in Zwischenablage kopieren", -- src\editor\menu_edit.lua - ["Correct &Indentation"] = "E&inzug korrigieren", -- src\editor\menu_edit.lua - ["Couldn't activate file '%s' for debugging; continuing without it."] = "Konnte Datei '%s' zwecks nicht Debugging aktivieren; fahre ohne die Datei fort.", -- src\editor\debugger.lua - ["Create an empty document"] = "Leeres Dokument anlegen", -- src\editor\toolbar.lua, src\editor\menu_file.lua - ["Cu&t"] = "A&usschneiden", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["Cut selected text to clipboard"] = "Schneide ausgewählten Text in die Zwischenablage hinein", -- src\editor\menu_edit.lua - ["Debugger server started at %s:%d."] = "Debugserver gestartet als %s:%d.", -- src\editor\debugger.lua - ["Debugger server stopped at %s:%d."] = "Debugserver gestoppt als %s:%d.", -- src\editor\debugger.lua - ["Debugging session completed (%s)."] = "Debugging Session beendet (%s).", -- src\editor\debugger.lua - ["Debugging session started in '%s'."] = "Debugging Session gestartet '%s'.", -- src\editor\debugger.lua - ["Debugging suspended at '%s:%s' (couldn't activate the file)."] = "Debugging angehalten bei '%s:%s' (konnte Datei nicht aktivieren).", -- src\editor\debugger.lua - ["Detach &Process"] = "Prozeß abkoppeln", -- src\editor\menu_project.lua - ["Disable Indexing For '%s'"] = "Indizieren ausschalten für '%s'", -- src\editor\outline.lua - ["Do you want to delete '%s'?"] = "Soll '%s' gelöscht werden?", -- src\editor\filetree.lua - ["Do you want to overwrite it?"] = "Überschreiben?", -- src\editor\commands.lua - ["Do you want to reload it?"] = "Neu laden?", -- src\editor\editor.lua - ["Do you want to save the changes to '%s'?"] = "Änderungen an '%s' speichern?", -- src\editor\commands.lua - ["E&xit"] = "&Beenden", -- src\editor\menu_file.lua - ["Enable Indexing"] = "Indizieren aktivieren", -- src\editor\outline.lua - ["Enter Lua code and press Enter to run it."] = "Lua-Code eingeben und Enter drücken zum Ausführen.", -- src\editor\shellbox.lua - ["Enter command line parameters (use Cancel to clear)"] = "Kommandozeilenparameter eingeben (Cancel zum löschen)", -- src\editor\menu_project.lua - ["Enter replacement text"] = "Neuen Text eingeben", -- src\editor\editor.lua - ["Error while loading API file: %s"] = "Fehler beim Laden von API-Datei: %s", -- src\editor\autocomplete.lua - ["Error while loading configuration file: %s"] = "Fehler beim Laden von Konfigurationsdatei: %s", -- src\editor\style.lua - ["Error while processing API file: %s"] = "Fehler beim Lesen von API-Datei: %s", -- src\editor\autocomplete.lua - ["Error while processing configuration file: %s"] = "Fehler beim Lesen von Konfiguratonsdatei: %s", -- src\editor\style.lua - ["Error"] = "Fehler", -- src\editor\commands.lua - ["Evaluate In Console"] = "In Konsole auswerten", -- src\editor\editor.lua - ["Execute the current project/file and keep updating the code to see immediate results"] = "Aktuelles Projekt/ aktuelle Datei ausführen und Quellcode ändern, um Ergebnisse in Echtzeit zu sehen", -- src\editor\menu_project.lua - ["Execute the current project/file"] = "Aktuelles Projekt/ aktuelle Datei ausführen", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Execution error"] = "Fehler bei Ausführung", -- src\editor\debugger.lua - ["Exit program"] = "Programm beenden", -- src\editor\menu_file.lua - ["File '%s' has been modified on disk."] = "Datei '%s' wurde auf der Festplatte geändert.", -- src\editor\editor.lua - ["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "Datei '%s' hat neueren Zeitstempel als wiederhergestellte Datei '%s'; bitte vor dem Speichern kontrollieren.", -- src\editor\commands.lua - ["File '%s' is missing and can't be recovered."] = "Datei '%s' fehlt und kann nicht wiederhergestellt werden.", -- src\editor\commands.lua - ["File '%s' no longer exists."] = "Datei '%s' existiert nicht mehr.", -- src\editor\menu_file.lua, src\editor\editor.lua - ["File already exists."] = "Datei existiert bereits.", -- src\editor\commands.lua - ["File history"] = "Dateiverlauf", -- src\editor\menu_file.lua - ["Find &In Files"] = "Finde &in Dateien", -- src\editor\menu_search.lua - ["Find &Next"] = "Finde &Nächste", -- src\editor\menu_search.lua - ["Find &Previous"] = "Finde &Vorherige", -- src\editor\menu_search.lua - ["Find and insert library function"] = "Suchen und Einfügen von Funktion aus Bibliothek", -- src\editor\menu_search.lua - ["Find and replace text in files"] = "Finde und ersetze Text in Dateien", -- src\editor\menu_search.lua - ["Find and replace text"] = "Finde und ersetze Text", -- src\editor\toolbar.lua, src\editor\menu_search.lua - ["Find in files"] = "Finde in dateien", -- src\editor\toolbar.lua - ["Find text in files"] = "Finde Text in Dateien", -- src\editor\menu_search.lua - ["Find text"] = "Finde Text", -- src\editor\toolbar.lua, src\editor\menu_search.lua - ["Find the earlier text occurence"] = "Finde vorheriges Auftreten des Textes", -- src\editor\menu_search.lua - ["Find the next text occurrence"] = "Finde nächstes Auftreten des Textes", -- src\editor\menu_search.lua - ["Find"] = "Finden", -- src\editor\toolbar.lua - ["Fold or unfold all code folds"] = "Alle Stellen im Code ein-/ausklappen ", -- src\editor\menu_edit.lua - ["Formatting page %d..."] = nil, -- src\editor\print.lua - ["Found %d instance."] = {"Eine Instanz gefunden", "%d Instanzen gefunden."}, -- src\editor\findreplace.lua - ["Found auto-recovery record and restored saved session."] = "Autowiederherstellen-Aufzeichnung gefunden und vorherige Sitzung wiederhergestellt.", -- src\editor\commands.lua - ["Full &Screen"] = "&Vollbild", -- src\editor\menu_view.lua - ["Go To Definition"] = "Gehe zu Definition", -- src\editor\editor.lua - ["Go To File..."] = "Gehe zu Datei...", -- src\editor\menu_search.lua - ["Go To Line..."] = "Gehe zu Zeile...", -- src\editor\menu_search.lua - ["Go To Next Bookmark"] = "Zu nächstem Lesezeichen", -- src\editor\menu_edit.lua - ["Go To Next Breakpoint"] = nil, -- src\editor\menu_project.lua - ["Go To Previous Bookmark"] = "Zu vorherigem Lesezeichen", -- src\editor\menu_edit.lua - ["Go To Previous Breakpoint"] = nil, -- src\editor\menu_project.lua - ["Go To Symbol..."] = "Gehe zu Symbol...", -- src\editor\menu_search.lua - ["Go to file"] = "Gehe zu Datei", -- src\editor\menu_search.lua - ["Go to line"] = "Gehe zu Zeile", -- src\editor\menu_search.lua - ["Go to symbol"] = "Gehe zu Symbol", -- src\editor\menu_search.lua - ["Hide '.%s' Files"] = "Verstecke '.%s' Dateien", -- src\editor\filetree.lua - ["INS"] = "INS", -- src\editor\editor.lua - ["Ignore and don't index symbols from files in the selected directory"] = "Dateien im ausgewählten Verzeichnis ignorieren und keine Symbole indizieren.", -- src\editor\outline.lua - ["Ignored error in debugger initialization code: %s."] = "Ignorierter Fehler im Debugger-Init-Code: %s.", -- src\editor\debugger.lua - ["Indexing %d files: '%s'..."] = "%d Dateien indizieren: '%s'...", -- src\editor\outline.lua - ["Indexing completed."] = "Indizierung abgeschlossen.", -- src\editor\outline.lua - ["Insert Library Function..."] = "Füge Funktion aus Bibliothek ein", -- src\editor\menu_search.lua - ["Known Files"] = "Bekannte Dateien", -- src\editor\commands.lua - ["Ln: %d"] = "Zeile: %d", -- src\editor\editor.lua - ["Local console"] = "Lokale Konsole", -- src\editor\gui.lua, src\editor\shellbox.lua - ["Lua &Interpreter"] = "&Lua Interpreter", -- src\editor\menu_project.lua - ["Map Directory..."] = "Verzeichnis virtuell einbinden...", -- src\editor\filetree.lua - ["Mapped remote request for '%s' to '%s'."] = "Fern-Aufforderung für '%s' auf '%s' abgebildet.", -- src\editor\debugger.lua - ["Markers Window"] = nil, -- src\editor\menu_view.lua - ["Markers"] = nil, -- src\editor\markers.lua - ["Match case"] = "Groß-/Kleinschreibung", -- src\editor\toolbar.lua - ["Match whole word"] = "Ganzes Wort", -- src\editor\toolbar.lua - ["Mixed end-of-line encodings detected."] = "Gemischte End-of-Line Kodierung entdeckt.", -- src\editor\commands.lua - ["Navigate"] = "Navigieren", -- src\editor\menu_search.lua - ["New &File"] = "Neue &Datei", -- src\editor\filetree.lua - ["OVR"] = "OVR", -- src\editor\editor.lua - ["Open With Default Program"] = "Mit Standardanwendung öffnen", -- src\editor\filetree.lua - ["Open an existing document"] = "Öffne existierendes Dokument", -- src\editor\toolbar.lua, src\editor\menu_file.lua - ["Open file"] = "Öffne Datei", -- src\editor\commands.lua - ["Outline Window"] = "Übersichtsfenster", -- src\editor\menu_view.lua - ["Outline"] = "Übersicht", -- src\editor\outline.lua - ["Output (running)"] = "Ausgabe (ausgeführt)", -- src\editor\debugger.lua, src\editor\output.lua - ["Output (suspended)"] = "Ausgabe (angehalten)", -- src\editor\debugger.lua - ["Output"] = "Ausgabe", -- src\editor\debugger.lua, src\editor\output.lua, src\editor\gui.lua, src\editor\settings.lua - ["Page Setup..."] = nil, -- src\editor\print.lua - ["Paste text from the clipboard"] = "Text aus Zwischenablage einfügen", -- src\editor\menu_edit.lua - ["Preferences"] = "Einstellungen", -- src\editor\menu_edit.lua - ["Prepend '!' to force local execution."] = "'!' voranstellen um lokale Ausführung zu erzwingen.", -- src\editor\shellbox.lua - ["Prepend '=' to show complex values on multiple lines."] = "'=' voranstellen, um komplexe Ausdrücke auf mehrere Zeilen zu verteilen.", -- src\editor\shellbox.lua - ["Press cancel to abort."] = "Abbrechen Drücken zum Beenden.", -- src\editor\commands.lua - ["Print the current document"] = nil, -- src\editor\print.lua - ["Program '%s' started in '%s' (pid: %d)."] = "Programm '%s' gestartet in '%s' (pid : %d).", -- src\editor\output.lua - ["Program can't start because conflicting process is running as '%s'."] = "Programm kann nicht starten, da blockierender Prozeß als '%s' läuft.", -- src\editor\output.lua - ["Program completed in %.2f seconds (pid: %d)."] = "Programm beendet nach %.2f Sekunden (pid : %d).", -- src\editor\output.lua - ["Program starting as '%s'."] = "Programm gestartet als '%s'.", -- src\editor\output.lua - ["Program stopped (pid: %d)."] = "Programm gestoppt (pid: %d).", -- src\editor\debugger.lua - ["Program unable to run as '%s'."] = "Programm kann nicht als '%s' laufen.", -- src\editor\output.lua - ["Project Directory"] = "&Projektverzeichnis", -- src\editor\menu_project.lua, src\editor\filetree.lua - ["Project history"] = "Liste bisheriger Projekte", -- src\editor\menu_file.lua - ["Project"] = "Projekt", -- src\editor\filetree.lua - ["Project/&FileTree Window"] = "&Projekt/Datei Fenster", -- src\editor\menu_view.lua - ["Provide command line parameters"] = "Kommandozeilenparameter angeben", -- src\editor\menu_project.lua - ["Queued %d files to index."] = "%d Dateien zum Indizieren vorgemerkt.", -- src\editor\menu_search.lua - ["R/O"] = "R/O", -- src\editor\editor.lua - ["R/W"] = "R/W", -- src\editor\editor.lua - ["Re&place In Files"] = "Ersetze in &Dateien", -- src\editor\menu_search.lua - ["Re-indent selected lines"] = "Ausgewählte Zeilen neu einrücken", -- src\editor\menu_edit.lua - ["Reached end of selection and wrapped around."] = nil, -- src\editor\findreplace.lua - ["Reached end of text and wrapped around."] = "Ende des Textes erreicht, setze am Beginn fort.", -- src\editor\findreplace.lua - ["Recent Files"] = "Letzte Dateien", -- src\editor\menu_file.lua - ["Recent Projects"] = "Letzte Projekte", -- src\editor\menu_file.lua - ["Redo last edit undone"] = "Stelle letzte rückgängig gemachte Bearbeitung wieder her", -- src\editor\menu_edit.lua - ["Refresh Index"] = "Index erneuern", -- src\editor\outline.lua - ["Refresh indexed symbols from files in the selected directory"] = "Erneuere indizierte Symbole in Dateien des ausgewählten Verzeichnisses", -- src\editor\outline.lua - ["Refresh"] = "Aktualisieren", -- src\editor\filetree.lua - ["Refused a request to start a new debugging session as there is one in progress already."] = "Starten einer neuen Debuggingsession abgelehnt, da bereits eine läuft.", -- src\editor\debugger.lua - ["Regular expression"] = "Regulärer Ausdruck", -- src\editor\toolbar.lua - ["Remote console"] = "Fernsteuerungs-Konsole", -- src\editor\shellbox.lua - ["Rename All Instances"] = "Umbenennen aller Instanzen", -- src\editor\editor.lua - ["Replace All Selections"] = "Alle Auswahlen ersetzen", -- src\editor\editor.lua - ["Replace all"] = "Alles ersetzen", -- src\editor\toolbar.lua - ["Replace next instance"] = "Nächste Instanz ersetzen", -- src\editor\toolbar.lua - ["Replaced %d instance."] = {"Eine Instanz ersetzt.", "%d Instanzen ersetzt."}, -- src\editor\findreplace.lua - ["Replaced an invalid UTF8 character with %s."] = "Unbekanntes UTF8-Symbol ersetzt mit %s.", -- src\editor\commands.lua - ["Reset to default layout"] = "Standard-Layout wiederherstellen", -- src\editor\menu_view.lua - ["Run As Scratchpad"] = "Als &Entwurf starten", -- src\editor\menu_project.lua - ["Run To Cursor"] = "Stoppe Ausführung an Cursorposition", -- src\editor\menu_project.lua, src\editor\editor.lua - ["Run as Scratchpad"] = "Als &Entwurf starten", -- src\editor\toolbar.lua - ["Run to cursor"] = "Stoppe Ausführung an Cursorposition", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["S&top Debugging"] = "Debugging a&nhalten", -- src\editor\menu_project.lua - ["S&top Process"] = "Prozeß &anhalten", -- src\editor\menu_project.lua - ["Save &As..."] = "S&peichern als...", -- src\editor\gui.lua, src\editor\menu_file.lua - ["Save A&ll"] = "&Alle Speichern", -- src\editor\menu_file.lua - ["Save Changes?"] = "Änderungen speichern?", -- src\editor\commands.lua - ["Save all open documents"] = "Alle offenen Dokumente speichern", -- src\editor\toolbar.lua, src\editor\menu_file.lua - ["Save file as"] = "Datei speichern als", -- src\editor\commands.lua - ["Save file?"] = "Datei speichern?", -- src\editor\commands.lua - ["Save the current document to a file with a new name"] = "Aktuelles Dokument unter neuem Namen speichern", -- src\editor\menu_file.lua - ["Save the current document"] = "Aktuelles Dokument speichern", -- src\editor\toolbar.lua, src\editor\menu_file.lua - ["Saved auto-recover at %s."] = "%s Autowiederherstellen gespeichert.", -- src\editor\commands.lua - ["Scratchpad error"] = "Fehler im Entwurf", -- src\editor\debugger.lua - ["Search direction"] = "Suchrichtung", -- src\editor\toolbar.lua - ["Search in selection"] = nil, -- src\editor\toolbar.lua - ["Search in subdirectories"] = "Suche in Unterverzeichnissen", -- src\editor\toolbar.lua - ["Searching for '%s'."] = "Suche nach '%s'.", -- src\editor\findreplace.lua - ["Sel: %d/%d"] = "Ausgew.: %d/%d", -- src\editor\editor.lua - ["Select &All"] = "&Alles Auswählen", -- src\editor\gui.lua, src\editor\editor.lua, src\editor\menu_edit.lua - ["Select And Find Next"] = "Auswählen und nächstes finden", -- src\editor\menu_search.lua - ["Select And Find Previous"] = "Auswählen und vorheriges finden", -- src\editor\menu_search.lua - ["Select all text in the editor"] = "Kompletten Text im Editor auswählen", -- src\editor\menu_edit.lua - ["Select the word under cursor and find its next occurrence"] = "Wort unter dem Cursor auswählen und nächstes Auftauchen finden", -- src\editor\menu_search.lua - ["Select the word under cursor and find its previous occurrence"] = "Wort unter dem Cursor auswählen und vorheriges Auftauchen finden", -- src\editor\menu_search.lua - ["Set As Start File"] = "Als Startdatei definieren.", -- src\editor\filetree.lua - ["Set From Current File"] = "Anhand der aktuellen Datei festlegen", -- src\editor\menu_project.lua - ["Set To Project Directory"] = "Setze als Projektverzeichnis", -- src\editor\findreplace.lua - ["Set To Selected Directory"] = nil, -- src\editor\filetree.lua - ["Set project directory from current file"] = "Lege Projektverzeichnis anhand der aktuellen Datei fest", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Set project directory to the selected one"] = nil, -- src\editor\filetree.lua - ["Set search directory"] = "Setze Suchverzeichnis", -- src\editor\toolbar.lua - ["Set the interpreter to be used"] = "Wähle zu benutzenden Interpreter aus", -- src\editor\menu_project.lua - ["Set the project directory to be used"] = "Lege zu benutzendes Projektverzeichnis fest", -- src\editor\menu_project.lua, src\editor\filetree.lua - ["Settings: System"] = "Einstellungen: System", -- src\editor\menu_edit.lua - ["Settings: User"] = "Einstellungen: Nutzer", -- src\editor\menu_edit.lua - ["Show &Tooltip"] = "&Tooltip zeigen", -- src\editor\menu_edit.lua - ["Show All Files"] = "Zeige alle Dateien", -- src\editor\filetree.lua - ["Show Hidden Files"] = "Zeige versteckte Dateien", -- src\editor\filetree.lua - ["Show Location"] = "Ordner öffnen", -- src\editor\gui.lua, src\editor\filetree.lua - ["Show all files"] = "Zeige alle Dateien", -- src\editor\filetree.lua - ["Show context"] = "Zeige Kontext", -- src\editor\toolbar.lua - ["Show files previously hidden"] = "Zeige Dateien die zuvor versteckt wurden", -- src\editor\filetree.lua - ["Show multiple result windows"] = "Zeige mehrere Ergebnisfenster", -- src\editor\toolbar.lua - ["Show tooltip for current position; place cursor after opening bracket of function"] = "Zeige Tooltip für aktuelle Position; setze Cursor hinter die öffnende Klammer der Funktion", -- src\editor\menu_edit.lua - ["Show/Hide the status bar"] = "Statuszeile zeigen/verstecken", -- src\editor\menu_view.lua - ["Show/Hide the toolbar"] = "Werkzeugleiste zeigen/verstecken", -- src\editor\menu_view.lua - ["Sort By Name"] = "Sortiere nach Namen", -- src\editor\outline.lua - ["Sort selected lines"] = "Ausgewählte Zeilen sortieren", -- src\editor\menu_edit.lua - ["Source"] = "Source", -- src\editor\menu_edit.lua - ["Stack"] = "Stack", -- src\editor\debugger.lua - ["Start &Debugging"] = "&Debugging starten", -- src\editor\menu_project.lua - ["Start or continue debugging"] = "Debuggen starten/fortsetzen", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Step &Into"] = "Schritt h&inein", -- src\editor\menu_project.lua - ["Step &Over"] = "&Überspringen", -- src\editor\menu_project.lua - ["Step O&ut"] = "Schritt &raus", -- src\editor\menu_project.lua - ["Step into"] = "Schritt hinein", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Step out of the current function"] = "Schritt aus der aktuellen Funktion heraus", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Step over"] = "Überspringen", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Stop debugging and continue running the process"] = "Beende debuggen und setze den Prozeß fort", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Stop the currently running process"] = "Aktuell laufenden Prozeß stoppen", -- src\editor\toolbar.lua, src\editor\menu_project.lua - ["Switch to or from full screen mode"] = "Vollbild an/aus", -- src\editor\menu_view.lua - ["Symbol Index"] = "Symbolindex", -- src\editor\outline.lua - ["Text not found."] = "Text nicht gefunden.", -- src\editor\findreplace.lua - ["The API file must be located in a subdirectory of the API directory."] = "Die API-Datei muß sich in einem Unterverzeichnis des API-Verzeichnisses befinden.", -- src\editor\autocomplete.lua - ["Toggle Bookmark"] = "Lesezeichen setzen/löschen", -- src\editor\markers.lua, src\editor\menu_edit.lua - ["Toggle Breakpoint"] = "Haltepunkt an/aus", -- src\editor\markers.lua, src\editor\menu_project.lua - ["Toggle bookmark"] = "Lesezeichen setzen/löschen", -- src\editor\toolbar.lua, src\editor\menu_edit.lua, src\editor\markers.lua - ["Toggle breakpoint"] = "Haltepunkt an/aus", -- src\editor\markers.lua, src\editor\toolbar.lua - ["Tr&ace"] = "Ablauf &verfolgen", -- src\editor\menu_project.lua - ["Trace execution showing each executed line"] = "Ablaufverfolgung zeigt jede ausgeführte Zeile an", -- src\editor\menu_project.lua - ["Unable to create directory '%s'."] = "Kann kein Verzeichnis '%s' erstellen.", -- src\editor\filetree.lua - ["Unable to create file '%s'."] = "Kann Datei '%s' nicht erstellen.", -- src\editor\filetree.lua - ["Unable to delete directory '%s': %s"] = "Scheitern beim Löschen von Verzeichnis '%s': %s", -- src\editor\filetree.lua - ["Unable to delete file '%s': %s"] = "Kann Datei '%s' nicht löschen: %s", -- src\editor\filetree.lua - ["Unable to load file '%s'."] = "Scheitern beim Laden von Datei '%s'.", -- src\editor\commands.lua - ["Unable to rename file '%s'."] = "Scheitern beim umbenennen von Datei '%s'.", -- src\editor\filetree.lua - ["Unable to save file '%s': %s"] = "Scheitern beim Speichern von Datei '%s' : %s", -- src\editor\commands.lua - ["Unable to stop program (pid: %d), code %d."] = "Scheitern beim Stoppen des Prozesses (pid : %d), code %d.", -- src\editor\debugger.lua - ["Undo last edit"] = "Letzte Änderung rückgängig machen", -- src\editor\menu_edit.lua - ["Unmap Directory"] = "virtuelle Einbindung beenden", -- src\editor\filetree.lua - ["Unset '%s' As Start File"] = "'%s' ist nicht mehr Startdatei", -- src\editor\filetree.lua - ["Updated %d file."] = {"Eine Datei aktualisiert", "%d Dateien aktualisiert."}, -- src\editor\findreplace.lua - ["Updating symbol index and settings..."] = "Aktualisiere Symbolindex und Einstellungen...", -- src\editor\outline.lua - ["Use %s to close."] = "%s zum Schließen.", -- src\editor\findreplace.lua - ["Use '%s' to see full description."] = "'%s' für eine komplette Beschreibung.", -- src\editor\editor.lua - ["Use '%s' to show line endings and '%s' to convert them."] = "'%s' um Zeilenende-Codes zu sehen, und '%s' um sie zu konvertieren.", -- src\editor\commands.lua - ["Use 'clear' to clear the shell output and the history."] = "'clear' um Ausgabefenster und Verlauf zu löschen.", -- src\editor\shellbox.lua - ["Use Shift-Enter for multiline code."] = " für Code in mehreren Zeilen.", -- src\editor\shellbox.lua - ["View the markers window"] = nil, -- src\editor\menu_view.lua - ["View the outline window"] = "Übersichtsfenster ansehen", -- src\editor\menu_view.lua - ["View the output/console window"] = "Ausgabe-/Konsolenfenster ansehen", -- src\editor\menu_view.lua - ["View the project/filetree window"] = "Projekt-/Dateifenster ansehen", -- src\editor\menu_view.lua - ["View the stack window"] = "Stapel/Stack-Fenster ansehen", -- src\editor\toolbar.lua, src\editor\menu_view.lua - ["View the watch window"] = "Fenster für Beobachtungspunkte ansehen", -- src\editor\toolbar.lua, src\editor\menu_view.lua - ["Watch"] = "Beobachtungspunkte", -- src\editor\debugger.lua - ["Welcome to the interactive Lua interpreter."] = "Willkommen zum interaktiven Lua-Interpretr!", -- src\editor\shellbox.lua - ["Wrap around"] = "Am Anfang fortsetzen", -- src\editor\toolbar.lua - ["You must save the program first."] = "Erst das Programm speichern.", -- src\editor\commands.lua - ["Zoom In"] = "Hineinzoomen", -- src\editor\menu_view.lua - ["Zoom Out"] = "Herauszoomen", -- src\editor\menu_view.lua - ["Zoom to 100%"] = "Zoom zurücksetzen (100%)", -- src\editor\menu_view.lua - ["Zoom"] = "Zoom", -- src\editor\menu_view.lua - ["on line %d"] = "in Zeile %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua - ["traced %d instruction"] = {"%d Anweisung verfolgt", "%d Anweisungen verfolgt"}, -- src\editor\debugger.lua - ["unknown error"] = "Unbekannter Fehler", -- src\editor\debugger.lua -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/en.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/en.lua deleted file mode 100644 index 16e9b98..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/i18n/en.lua +++ /dev/null @@ -1,7 +0,0 @@ -return { - [0] = function(c) return c == 1 and 1 or 2 end, -- plural - ["traced %d instruction"] = {"traced %d instruction", "traced %d instructions"}, -- src\editor\debugger.lua - ["Found %d instance."] = {"Found %d instance.", "Found %d instances."}, -- src\editor\findreplace.lua - ["Replaced %d instance."] = {"Replaced %d instance.", "Replaced %d instances."}, -- src\editor\findreplace.lua - ["Updated %d file."] = {"Updated %d file.", "Updated %d files."}, -- src\editor\findreplace.lua -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/scheme-picker.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/scheme-picker.lua deleted file mode 100644 index 0a3ffde..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/scheme-picker.lua +++ /dev/null @@ -1,28 +0,0 @@ ---[[ -1. Pick a color scheme by clicking on its name: - - [Tomorrow](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Tomorrow'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [TomorrowContrast](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowContrast'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [TomorrowNight](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNight'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [TomorrowNightBlue](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBlue'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [TomorrowNightBright](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBright'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [TomorrowNightEighties](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightEighties'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [Zenburn](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Zenburn'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [Monokai](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Monokai'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [Molokai](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Molokai'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [SolarizedDark](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedDark'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [SolarizedLight](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedLight'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [Notepad++](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','NotepadPlusPlus'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - [SciTeLuaIDE](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SciTeLuaIDE'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles())) - - - [ZeroBrane Studio](macro:inline(ide.config.styles = StylesGetDefault(); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = {}; ReApplySpecAndStyles())) - -2. Add the following code with the scheme you selected to `cfg/user.lua`. ---]] - -styles = loadfile('cfg/tomorrow.lua')('TomorrowNightBlue') -stylesoutshell = styles -- apply the same scheme to Output/Console windows -styles.auxwindow = styles.text -- apply text colors to auxiliary windows -styles.calltip = styles.text -- apply text colors to tooltips - --- code example -if false and true then func(1, 2, 3) end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/tomorrow.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/tomorrow.lua deleted file mode 100644 index 6d88f7f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/tomorrow.lua +++ /dev/null @@ -1,311 +0,0 @@ --- This is a file that sets color scheme based on Tomorrow format. --- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC - --- Tomorrow colors from https://github.com/chriskempson/tomorrow-theme --- Zenburn colors from https://github.com/jnurmine/Zenburn/blob/master/colors/zenburn.vim (contributed by Srdjan Marković) --- Monokai colors from http://www.monokai.nl/blog/2006/07/15/textmate-color-theme/ --- Molokai colors based on https://github.com/tomasr/molokai/blob/master/colors/molokai.vim --- Solarized colors from https://github.com/altercation/vim-colors-solarized - -local theme = ... - -local function h2d(n) return 0+('0x'..n) end -local function H(c, bg) c = c:gsub('#','') - -- since alpha is not implemented, convert RGBA to RGB - -- assuming 0 is transparent and 255 is opaque - -- based on http://stackoverflow.com/a/2645218/1442917 - local bg = bg and H(bg) or {255, 255, 255} - local a = #c > 6 and h2d(c:sub(7,8))/255 or 1 - local r, g, b = h2d(c:sub(1,2)), h2d(c:sub(3,4)), h2d(c:sub(5,6)) - return { - math.min(255, math.floor((1-a)*bg[1]+a*r)), - math.min(255, math.floor((1-a)*bg[2]+a*g)), - math.min(255, math.floor((1-a)*bg[3]+a*b))} -end - -local colors = { - Tomorrow = { - Background = H'ffffff', - CurrentLine = H'efefef', - Selection = H'd6d6d6', - Foreground = H'4d4d4c', - Comment = H'8e908c', - Red = H'c82829', - Orange = H'f5871f', - Yellow = H'eab700', - Green = H'718c00', - Aqua = H'3e999f', - Blue = H'4271ae', - Purple = H'8959a8', - }, - TomorrowContrast = { -- contributed by Sergey Lerg - Background = H'f7f7f7', - CurrentLine = H'efefef', - Selection = H'd6d6d6', - Foreground = H'202020', - Comment = H'8e908c', - Red = H'4669ff', --numbers - Orange = H'f5871f', - Yellow = H'eab700', - Green = H'108010', --strings - Aqua = H'4060b0', --built in functions - Blue = H'101080', --keywords - Purple = H'a01090', - }, - TomorrowNight = { - Background = H'1d1f21', - CurrentLine = H'282a2e', - Selection = H'373b41', - Foreground = H'c5c8c6', - Comment = H'969896', - Red = H'cc6666', - Orange = H'de935f', - Yellow = H'f0c674', - Green = H'b5bd68', - Aqua = H'8abeb7', - Blue = H'81a2be', - Purple = H'b294bb', - }, - TomorrowNightEighties = { - Background = H'2d2d2d', - CurrentLine = H'393939', - Selection = H'515151', - Foreground = H'cccccc', - Comment = H'999999', - Red = H'f2777a', - Orange = H'f99157', - Yellow = H'ffcc66', - Green = H'99cc99', - Aqua = H'66cccc', - Blue = H'6699cc', - Purple = H'cc99cc', - }, - TomorrowNightBlue = { - Background = H'002451', - CurrentLine = H'00346e', - Selection = H'003f8e', - Foreground = H'ffffff', - Comment = H'7285b7', - Red = H'ff9da4', - Orange = H'ffc58f', - Yellow = H'ffeead', - Green = H'd1f1a9', - Aqua = H'99ffff', - Blue = H'bbdaff', - Purple = H'ebbbff', - }, - TomorrowNightBright = { - Background = H'000000', - CurrentLine = H'2a2a2a', - Selection = H'424242', - Foreground = H'eaeaea', - Comment = H'969896', - Red = H'd54e53', - Orange = H'e78c45', - Yellow = H'e7c547', - Green = H'b9ca4a', - Aqua = H'70c0b1', - Blue = H'7aa6da', - Purple = H'c397d8', - }, - Zenburn = { - Background = H'3f3f3f', - CurrentLine = H'363636', - Selection = H'1f1f1f', - Foreground = H'dcdccc', - Comment = H'7f9f7f', - Red = H'8cd0d3', - Orange = H'dfaf8f', - Yellow = H'e3ceab', - Green = H'cc9393', - Aqua = H'dca3a3', - Blue = H'f0dfaf', - Purple = H'efef8f', - }, - Monokai = { - Background = H'272822', - CurrentLine = H'2D2F29', - Selection = H'49483E', - Foreground = H'F8F8F2', - Comment = H'75715E', - Red = H'AE81FF', - Orange = H'AE81FF', - Yellow = H'F8F8F2', - Green = H'E6DB74', - Aqua = H'66D9EF', - Blue = H'F92672', - Purple = H'A6E22E', - }, - Molokai = { - Background = H'1B1D1E', - CurrentLine = H'293739', - Selection = H'49483E', - Foreground = H'F8F8F2', - Comment = H'7E8E91', - Red = H'AE81FF', - Orange = H'AE81FF', - Yellow = H'F8F8F2', - Green = H'E6DB74', - Aqua = H'66D9EF', - Blue = H'F92672', - Purple = H'A6E22E', - }, - SolarizedDark = { - Background = H'042029', - CurrentLine = H'0A2933', - Selection = H'073642', - Foreground = H'839496', - Comment = H'586E75', - Red = H'D33682', - Orange = H'B58900', - Yellow = H'839496', - Green = H'2AA198', - Aqua = H'839496', - Blue = H'859900', - Purple = H'268BD2', - }, - SolarizedLight = { - Background = H'FDF6E3', - CurrentLine = H'EEE8D5', - Selection = H'E0E0D0', - Foreground = H'586E75', - Comment = H'93A1A1', - Red = H'D33682', - Orange = H'B58900', - Yellow = H'586E75', - Green = H'2AA198', - Aqua = H'586E75', - Blue = H'859900', - Purple = H'268BD2', - }, - NotepadPlusPlus = { -- contributed by Florian (https://github.com/SiENcE) - Background = H'FFFFFF', - CurrentLine = H'E9E2FF', - Selection = H'C0C0C0', - Foreground = H'000000', - Comment = H'008000', - Red = H'FF6900', - Orange = H'FF0000', - Yellow = H'FF4E00', - Green = H'808080', - Aqua = H'000080', - Blue = H'2123FF', - Purple = H'8000FF', - }, - SciTeLuaIDE = { -- contributed by Jayanth Acharya - Background = H'1B1D1E', - CurrentLine = H'293739', - Selection = H'49483E', - Foreground = H'F8F8F2', -- super-light-gray (everything else) - Comment = H'00FF00', -- bright green (comments) - Red = H'F92672', -- purple (numbers) - Orange = H'AE81FF', -- lavendar?? (numbers) - Yellow = H'F8F8F2', -- light-gray - Green = H'FF8000', -- amber (string literal) - Aqua = H'808080', -- gray (operators, separators etc.) - Blue = H'0066FF', -- semi-blue (keywords) - Purple = H'A6E22E', -- light-grass-green - }, -} - --- add more of the specified color (keeping all in 0-255 range) -local mixer = function(c, n, more) - if not c or #c == 0 then return c end - local c = {c[1], c[2], c[3]} -- create a copy, so it can be modified - c[n] = c[n] + more - local excess = c[n] - 255 - if excess > 0 then - for clr = 1, 3 do - c[clr] = n == clr and 255 or c[clr] > excess and c[clr] - excess or 0 - end - end - return c -end - -local C = colors[theme] or colors.Tomorrow -return { - -- wxstc.wxSTC_LUA_DEFAULT - lexerdef = {fg = C.Foreground}, - -- wxstc.wxSTC_LUA_COMMENT, wxstc.wxSTC_LUA_COMMENTLINE, wxstc.wxSTC_LUA_COMMENTDOC - comment = {fg = C.Comment, fill = true}, - -- wxstc.wxSTC_LUA_STRING, wxstc.wxSTC_LUA_CHARACTER, wxstc.wxSTC_LUA_LITERALSTRING - stringtxt = {fg = C.Green}, - -- wxstc.wxSTC_LUA_STRINGEOL - stringeol = {fg = C.Green, fill = true}, - -- wxstc.wxSTC_LUA_PREPROCESSOR - preprocessor = {fg = C.Orange}, - -- wxstc.wxSTC_LUA_OPERATOR - operator = {fg = C.Aqua}, - -- wxstc.wxSTC_LUA_NUMBER - number = {fg = C.Red}, - - -- wxstc.wxSTC_LUA_WORD, wxstc.wxSTC_LUA_WORD2-8 - keywords0 = {fg = C.Blue, b = true}, - keywords1 = {fg = C.Aqua, b = false}, - keywords2 = {fg = C.Aqua, b = true}, - keywords3 = {fg = C.Purple, b = false}, - keywords4 = {fg = C.Purple, b = false}, - keywords5 = {fg = C.Purple, b = false}, - keywords6 = {fg = C.Purple, b = false}, - keywords7 = {fg = C.Purple, b = false}, - - -- common (inherit fg/bg from text) - -- wxstc.wxSTC_LUA_IDENTIFIER - text = {fg = C.Foreground, bg = C.Background}, - linenumber = {fg = C.Comment}, - bracematch = {fg = C.Orange, b = true}, - bracemiss = {fg = C.Red, b = true}, - ctrlchar = {fg = C.Yellow}, - indent = {fg = C.Comment}, - calltip = nil, - - -- common special (need custom fg & bg) - sel = {bg = C.Selection}, - caret = {fg = C.Foreground}, - caretlinebg = {bg = C.CurrentLine}, - fold = {fg = C.Comment, bg = C.Background, sel = mixer(C.Comment, 1, 96)}, - whitespace = {fg = C.Comment, bg = C.Background}, - edge = {}, - - indicator = { - fncall = {fg = C.Purple, st = wxstc.wxSTC_INDIC_HIDDEN}, - --[[ other possible values are: - wxSTC_INDIC_PLAIN Single-line underline - wxSTC_INDIC_SQUIGGLE Squiggly underline - wxSTC_INDIC_TT Line of small T-shapes - wxSTC_INDIC_DIAGONAL Diagonal hatching - wxSTC_INDIC_STRIKE Strike-out - wxSTC_INDIC_BOX Box - wxSTC_INDIC_ROUNDBOX Rounded Box - --]] - -- these indicators have all different default styles - varlocal = {fg = C.Foreground}, - varglobal = {fg = C.Foreground}, - varmasked = {fg = C.Foreground}, - varmasking = {fg = C.Foreground}, - }, - - -- markup - ['['] = {hs = mixer(C.Comment, 3, 64)}, - ['|'] = {fg = mixer(mixer(C.Comment, 1, 64), 3, 64)}, - - -- markers - marker = { - message = {bg = C.Selection}, - output = {bg = C.CurrentLine}, - prompt = {fg = C.Foreground, bg = C.Background}, - error = {bg = mixer(C.Background, 1, 32)}, - }, -} - ---[[ - ----- Solarized license ---- - -Copyright (c) 2011 Ethan Schoonover - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---]] diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user-sample.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user-sample.lua deleted file mode 100644 index 302ccf2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user-sample.lua +++ /dev/null @@ -1,170 +0,0 @@ ---[[-- This file shows examples of settings you can adjust. - -Configuration files with preferences are loaded in the following order: -1. cfg/user.lua (system-wide configuration) -2. HOME/.zbstudio/user.lua (per-user configuration) -3. -cfg (command line configuration) - -See [configuration](http://studio.zerobrane.com/doc-configuration.html) page for information about location of configuration files. - ---]]-- - --- to modify loaded configuration for recognized extensions for lua files --- (no longer needed in v1.21+) local G = ... -- this now points to the global environment -local luaspec = ide.specs.lua -luaspec.exts[#luaspec.exts+1] = "luaz" -luaspec.keywords[1] = luaspec.keywords[1] .. ' foo' - --- to modify a key mapping; see the full list of IDs in src/editor/keymap.lua --- starting from v0.95, ID. can be used instead of G.ID_ -keymap[ID.STARTDEBUG] = "Ctrl-Shift-D" - --- to change font size to 12 -editor.fontsize = 12 -- this is mapped to ide.config.editor.fontsize -editor.fontname = "Courier New" -filehistorylength = 20 -- this is mapped to ide.config.filehistorylength - --- to specify full path to love2d *executable*; this is only needed --- if the game folder and the executable are NOT in the same folder. -path.love2d = 'd:/lua/love/love' - --- to specify full path to moai *executable* if it's not in one of PATH folders -path.moai = 'd:/lua/moai/moai' --- Moai config.lua file is searched in the following places: (1) MOAI_CONFIG, --- (2) project directory (if set) or folder with the current file, --- (3) folder with the moai executable. - --- to specify full path to gideros *executable* if it's not in one of PATH folders -path.gideros = 'd:/Program Files/Gideros/GiderosPlayer.exe' - --- to specify full path to corona *executable* if it's not in one of PATH folders -path.corona = 'd:/path/to/Corona SDK/Corona Simulator.exe' - --- to specify full path to lua interpreter if you need to use your own version -path.lua = 'd:/lua/lua' - --- to specify full path to GSL-shell *executable* if it's not in one of PATH folders -path.gslshell = [[D:\Lua\gsl-shell\gsl-shell.exe]] - --- to provide output filter for those engines that support redirecting --- of "print" output to the IDE (like Corona SDK or Gideros) -debugger.outputfilter = function(m) return #m < 124 and m or m:sub(1,120).."...\n" end - --- to fix an issue with 0d0d0a line endings in MOAI examples, --- which may negatively affect breakpoints during debugging -editor.iofilter = "0d0d0aFix" - --- to have 4 spaces when TAB is used in the editor -editor.tabwidth = 4 - --- to have TABs stored in the file (to allow mixing tabs and spaces) -editor.usetabs = true - --- to disable wrapping of long lines in the editor -editor.usewrap = false - --- to turn dynamic words on and to start suggestions after 4 characters -acandtip.nodynwords = false -acandtip.startat = 4 - --- to automatically open files requested during debugging -editor.autoactivate = true - --- to specify a list of MOAI entrypoints -moai = { entrypoints = { "main.lua", "source/main.lua" } } - --- to specify language to use in the IDE (requires a file in cfg/i18n folder) -language = "ru" - --- to change background color (or other colors in the IDE); --- see cfg/tomorrow.lua for example/details on what other colors to change -styles.text = {bg = {240,240,220}} - --- to change the default color scheme; check tomorrow.lua for the list --- of supported schemes or use cfg/scheme-picker.lua to pick a scheme. --- (no longer needed in v1.21+) local G = ... -- this now points to the global environment -styles = loadfile('cfg/tomorrow.lua')('Tomorrow') --- also apply the same scheme to Output and Console windows -stylesoutshell = styles - --- to change markers used in console and output windows -styles.marker = styles.marker or {} -styles.marker.message = {ch = wxstc.wxSTC_MARK_ARROWS, fg = {0, 0, 0}, bg = {240, 240, 240}} -styles.marker.output = {ch = wxstc.wxSTC_MARK_BACKGROUND, fg = {0, 0, 0}, bg = {240, 240, 240}} -styles.marker.prompt = {ch = wxstc.wxSTC_MARK_CHARACTER+('>'):byte(), fg = {0, 0, 0}, bg = {240, 240, 240}} -stylesoutshell = styles - --- to disable indicators (underlining) on function calls --- styles.indicator.fncall = nil - --- to change the color of the indicator used for function calls -styles.indicator.fncall.fg = {240,0,0} - --- to change the type of the indicator used for function calls -styles.indicator.fncall.st = wxstc.wxSTC_INDIC_PLAIN - --[[ other possible values are: - wxSTC_INDIC_DOTS Dotted underline; wxSTC_INDIC_PLAIN Single-line underline - wxSTC_INDIC_TT Line of Tshapes; wxSTC_INDIC_SQUIGGLE Squiggly underline - wxSTC_INDIC_STRIKE Strike-out; wxSTC_INDIC_SQUIGGLELOW Squiggly underline (2 pixels) - wxSTC_INDIC_BOX Box; wxSTC_INDIC_ROUNDBOX Rounded Box - wxSTC_INDIC_DASH Dashed underline; wxSTC_INDIC_STRAIGHTBOX Box with trasparency - wxSTC_INDIC_DOTBOX Dotted rectangle; wxSTC_INDIC_DIAGONAL Diagonal hatching - wxSTC_INDIC_HIDDEN No visual effect; - --]] - --- to enable additional spec files (like spec/glsl.lua) -load.specs(function(file) return file:find('spec[/\\]glsl%.lua$') end) - --- to specify a default EOL encoding to be used for new files: --- `wxstc.wxSTC_EOL_CRLF` or `wxstc.wxSTC_EOL_LF`; --- `nil` means OS default: CRLF on Windows and LF on Linux/Unix and OSX. --- (OSX had CRLF as a default until v0.36, which fixed it). -editor.defaulteol = wxstc.wxSTC_EOL_LF - --- to turn off checking for mixed end-of-line encodings in loaded files -editor.checkeol = false - --- to force execution to continue immediately after starting debugging; --- set to `false` to disable (the interpreter will stop on the first line or --- when debugging starts); some interpreters may use `true` or `false` --- by default, but can be still reconfigured with this setting. -debugger.runonstart = true - --- to set compact fold that doesn't include empty lines after a block -editor.foldcompact = true - --- to disable zoom with mouse wheel as it may be too sensitive on OSX -editor.nomousezoom = true - --- to specify a skin for Corona simulator (OSX only); --- you can also change it between runs from Local Console by executing --- `ide.config.corona = {skin = 'iPad'}` -corona = { skin = "iPad" } - --- to style individual keywords; `return` and `break` are shown in red --- (no longer needed in v1.21+) local G = ... -- this now points to the global environment -local luaspec = ide.specs.lua - -local num = #luaspec.keywords --- take a new slot in the list of keywords (starting from 1) -luaspec.keywords[num+1] = 'return break' --- remove 'return' from the list of "regular" keywords -luaspec.keywords[1] = luaspec.keywords[1]:gsub(' return', ''):gsub(' break', '') - --- assign new style to the added slot (starting from 0) -styles["keywords"..num] = {fg = {240, 0, 0}, b = true} - --- enable `Opt+Shift+Left/Right` shortcut on OSX -editor.keymap[#editor.keymap+1] = {wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_ALT+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_WORDLEFTEXTEND, "Macintosh"} -editor.keymap[#editor.keymap+1] = {wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_ALT+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_WORDRIGHTENDEXTEND, "Macintosh"} - --- enable Emacs bindings to use `Ctrl-A` and `Ctrl-E` to go to the line start/end -editor.keymap[#editor.keymap+1] = {('A'):byte(), wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_HOME} -editor.keymap[#editor.keymap+1] = {('E'):byte(), wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_LINEEND} -keymap[ID.SELECTALL] = nil -- remove `Ctrl-A` shortcut from `SelectAll` - --- updated shortcuts to use them as of v1.20 -keymap[ID.BREAK] = "Shift-F9" -keymap[ID.BREAKPOINTTOGGLE] = "F9" -keymap[ID.BREAKPOINTNEXT] = "" -keymap[ID.BREAKPOINTPREV] = "" diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user.lua deleted file mode 100644 index 087df03..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/user.lua +++ /dev/null @@ -1,56 +0,0 @@ ---[[-- This file shows examples of settings you can adjust. - -Configuration files with preferences are loaded in the following order: -1. cfg/user.lua (system-wide configuration) -2. HOME/.zbstudio/user.lua (per-user configuration) -3. -cfg (command line configuration) - -See [configuration](http://studio.zerobrane.com/doc-configuration.html) page for information about location of configuration files. - ---]]-- - --- to modify a key mapping; see the full list of IDs in src/editor/keymap.lua --- starting from v0.95, ID. can be used instead of G.ID_ -keymap[ID.RUN] = "Ctrl-R" -keymap[ID.REPLACE] = nil - --- to change font size to 12 -editor.fontsize = 14 -- this is mapped to ide.config.editor.fontsize ---editor.fontname = "Courier New" -filehistorylength = 20 -- this is mapped to ide.config.filehistorylength - --- to specify full path to love2d *executable*; this is only needed --- if the game folder and the executable are NOT in the same folder. -path.love2d = '../tools/love.app' - --- to disable wrapping of long lines in the editor -editor.usewrap = true - --- to specify language to use in the IDE (requires a file in cfg/i18n folder) -language = "en" - --- do not offer dynamic (user entered) words; set to false to collect all words from all open editor tabs and offer them as part of the auto-complete list. -acandtip.nodynwords = true - --- to change the default color scheme; check tomorrow.lua for the list --- of supported schemes or use cfg/scheme-picker.lua to pick a scheme. --- (no longer needed in v1.21+) local G = ... -- this now points to the global environment -styles = loadfile('cfg/tomorrow.lua')('Tomorrow') - ---TURN OFF UNDERLINING -styles.indicator = {} - --- also apply the same scheme to Output and Console windows -stylesoutshell = styles - --- to set compact fold that doesn't include empty lines after a block ---editor.foldcompact = true - --- set the default interpreter used for new projects -interpreter = "love2d" - --- https://github.com/pkulchenko/ZeroBraneStudio/issues/645 -ide.interpreters.love2d.skipcompile=true - --- don't open output on run -activateoutput = false diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/xcode-keys.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/xcode-keys.lua deleted file mode 100644 index 2fec8a2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/cfg/xcode-keys.lua +++ /dev/null @@ -1,73 +0,0 @@ --- Copy the content of this file to user.lua; --- see the [configuration](http://studio.zerobrane.com/doc-configuration.html) page for details. - --- Alt-Shift-Cmd-X (Alt maps to Option, Ctrl maps to Command) --- The mapping is largely based on [Xcode Keyboard Shortcuts](http://developer.apple.com/library/mac/#documentation/IDEs/Conceptual/xcode_help-command_shortcuts/MenuCommands/MenuCommands014.html). -local xcode = { --- File menu - [ID.NEW] = "Ctrl-N", - [ID.OPEN] = "Ctrl-O", - [ID.CLOSE] = "Ctrl-W", - [ID.SAVE] = "Ctrl-S", - [ID.SAVEAS] = "Shift-Ctrl-S", - [ID.SAVEALL] = "Alt-Ctrl-S", - [ID.RECENTFILES] = "", - [ID.EXIT] = "Ctrl-Q", --- Edit menu - [ID.CUT] = "Ctrl-X", - [ID.COPY] = "Ctrl-C", - [ID.PASTE] = "Ctrl-V", - [ID.SELECTALL] = "Ctrl-A", - [ID.UNDO] = "Ctrl-Z", - [ID.REDO] = "Shift-Ctrl-Z", - [ID.SHOWTOOLTIP] = "Ctrl-T", - [ID.AUTOCOMPLETE] = "Ctrl-K", - [ID.AUTOCOMPLETEENABLE] = "", - [ID.COMMENT] = "Ctrl-U", - [ID.FOLD] = "F12", - [ID.CLEARDYNAMICWORDS] = "", --- Search menu - [ID.FIND] = "Ctrl-F", - [ID.FINDNEXT] = "Ctrl-G", - [ID.FINDPREV] = "Shift-Ctrl-G", - [ID.REPLACE] = "Alt-Ctrl-F", - [ID.FINDINFILES] = "Shift-Ctrl-F", - [ID.REPLACEINFILES] = "Alt-Shift-Ctrl-F", - [ID.SORT] = "", --- View menu - [ID.VIEWFILETREE] = "Shift-Ctrl-P", - [ID.VIEWOUTPUT] = "Shift-Ctrl-O", - [ID.VIEWWATCHWINDOW] = "Shift-Ctrl-W", - [ID.VIEWCALLSTACK] = "Shift-Ctrl-S", - [ID.VIEWDEFAULTLAYOUT] = "", - [ID.VIEWFULLSCREEN] = "Shift-Ctrl-A", --- Project menu - [ID.RUN] = "Ctrl-R", - [ID.RUNNOW] = "Shift-Ctrl-R", - [ID.COMPILE] = "Ctrl-B", - [ID.ANALYZE] = "Shift-Ctrl-B", - [ID.STARTDEBUG] = "F5", - [ID.ATTACHDEBUG] = "", - [ID.STOPDEBUG] = "Ctrl-.", - [ID.STEP] = "F7", - [ID.STEPOVER] = "F6", - [ID.STEPOUT] = "F8", - [ID.TRACE] = "", - [ID.BREAK] = "Ctrl-Y", - [ID.BREAKPOINTTOGGLE] = "Ctrl-\\", - [ID.CLEAROUTPUT] = "", - [ID.INTERPRETER] = "", - [ID.PROJECTDIR] = "", --- Help menu - [ID.ABOUT] = "F1", --- Watch window menu items - [ID.ADDWATCH] = "Ins", - [ID.EDITWATCH] = "F2", - [ID.DELETEWATCH] = "Del", --- Editor popup menu items - [ID.QUICKADDWATCH] = "", - [ID.QUICKEVAL] = "", -} - -local G = ... -for id, key in G.pairs(xcode) do keymap[id] = key end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/love2d.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/love2d.lua deleted file mode 100644 index 9059584..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/love2d.lua +++ /dev/null @@ -1,61 +0,0 @@ --- Copyright 2011-12 Paul Kulchenko, ZeroBrane LLC - -local love2d -local win = ide.osname == "Windows" -local mac = ide.osname == "Macintosh" - -return { - name = "LÖVE", - description = "LÖVE game engine", - api = {"baselib", "love2d"}, - frun = function(self,wfilename,rundebug) - love2d = love2d or ide.config.path.love2d -- check if the path is configured - if not love2d then - local sep = win and ';' or ':' - local default = - win and (GenerateProgramFilesPath('love', sep)..sep) - or mac and ('/Applications/love.app/Contents/MacOS'..sep) - or '' - local path = default - ..(os.getenv('PATH') or '')..sep - ..(GetPathWithSep(self:fworkdir(wfilename)))..sep - ..(os.getenv('HOME') and GetPathWithSep(os.getenv('HOME'))..'bin' or '') - local paths = {} - for p in path:gmatch("[^"..sep.."]+") do - love2d = love2d or GetFullPathIfExists(p, win and 'love.exe' or 'love') - table.insert(paths, p) - end - if not love2d then - DisplayOutputLn("Can't find love2d executable in any of the following folders: " - ..table.concat(paths, ", ")) - return - end - end - - if not GetFullPathIfExists(self:fworkdir(wfilename), 'main.lua') then - DisplayOutputLn(("Can't find 'main.lua' file in the current project folder: '%s'.") - :format(self:fworkdir(wfilename))) - return - end - - if rundebug then - DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true}) - end - - -- suppress hiding ConsoleWindowClass as this is used by Love console - local uhw = ide.config.unhidewindow - local cwc = uhw and uhw.ConsoleWindowClass - if uhw then uhw.ConsoleWindowClass = 0 end - - local params = ide.config.arg.any or ide.config.arg.love2d - local cmd = ('"%s" "%s"%s%s'):format(love2d, self:fworkdir(wfilename), - params and " "..params or "", rundebug and ' -debug' or '') - -- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback) - return CommandLineRun(cmd,self:fworkdir(wfilename),true,true,nil,nil, - function() if uhw then uhw.ConsoleWindowClass = cwc end end) - end, - hasdebugger = true, - fattachdebug = function(self) DebuggerAttachDefault() end, - scratchextloop = true, - takeparameters = true, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luabase.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luabase.lua deleted file mode 100644 index d33edc2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luabase.lua +++ /dev/null @@ -1,101 +0,0 @@ -function MakeLuaInterpreter(version, name) - -local function exePath(self, version) - local version = tostring(version):gsub('%.','') - local mainpath = ide.editorFilename:gsub("[^/\\]+$","") - local macExe = mainpath..([[bin/lua.app/Contents/MacOS/lua%s]]):format(version) - return ide.config.path['lua'..version] - or (ide.osname == "Windows" and mainpath..([[bin\lua%s.exe]]):format(version)) - or (ide.osname == "Unix" and mainpath..([[bin/linux/%s/lua%s]]):format(ide.osarch, version)) - or (wx.wxFileExists(macExe) and macExe or mainpath..([[bin/lua%s]]):format(version)) -end - -return { - name = ("Lua%s"):format(name or version or ""), - description = ("Lua%s interpreter with debugger"):format(name or version or ""), - api = {"baselib"}, - luaversion = version or '5.1', - fexepath = exePath, - frun = function(self,wfilename,rundebug) - local exe = self:fexepath(version or "") - local filepath = wfilename:GetFullPath() - - do - -- if running on Windows and can't open the file, this may mean that - -- the file path includes unicode characters that need special handling - local fh = io.open(filepath, "r") - if fh then fh:close() end - if ide.osname == 'Windows' and pcall(require, "winapi") - and wfilename:FileExists() and not fh then - winapi.set_encoding(winapi.CP_UTF8) - local shortpath = winapi.short_path(filepath) - if shortpath == filepath then - DisplayOutputLn( - ("Can't get short path for a Unicode file name '%s' to open the file.") - :format(filepath)) - DisplayOutputLn( - ("You can enable short names by using `fsutil 8dot3name set %s: 0` and recreate the file or directory.") - :format(wfilename:GetVolume())) - end - filepath = shortpath - end - end - - if rundebug then - DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true}) - - -- update arg to point to the proper file - rundebug = ('if arg then arg[0] = [[%s]] end '):format(filepath)..rundebug - - local tmpfile = wx.wxFileName() - tmpfile:AssignTempFileName(".") - filepath = tmpfile:GetFullPath() - local f = io.open(filepath, "w") - if not f then - DisplayOutputLn("Can't open temporary file '"..filepath.."' for writing.") - return - end - f:write(rundebug) - f:close() - end - local params = ide.config.arg.any or ide.config.arg.lua - local code = ([[-e "io.stdout:setvbuf('no')" "%s"]]):format(filepath) - local cmd = '"'..exe..'" '..code..(params and " "..params or "") - - -- modify CPATH to work with other Lua versions - local envname = "LUA_CPATH" - if version then - local env = "LUA_CPATH_"..string.gsub(version, '%.', '_') - if os.getenv(env) then envname = env end - end - - local cpath = os.getenv(envname) - if rundebug and cpath and not ide.config.path['lua'..(version or "")] then - -- prepend osclibs as the libraries may be needed for debugging, - -- but only if no path.lua is set as it may conflict with system libs - wx.wxSetEnv(envname, ide.osclibs..';'..cpath) - end - if version and cpath then - local cpath = os.getenv(envname) - local clibs = string.format('/clibs%s/', version):gsub('%.','') - if not cpath:find(clibs, 1, true) then cpath = cpath:gsub('/clibs/', clibs) end - wx.wxSetEnv(envname, cpath) - end - - -- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback) - local pid = CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil, - function() if rundebug then wx.wxRemoveFile(filepath) end end) - - if (rundebug or version) and cpath then wx.wxSetEnv(envname, cpath) end - return pid - end, - hasdebugger = true, - fattachdebug = function(self) DebuggerAttachDefault() end, - scratchextloop = false, - unhideanywindow = true, - takeparameters = true, -} - -end - -return nil -- as this is not a real interpreter diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb.lua deleted file mode 100644 index 49af279..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb.lua +++ /dev/null @@ -1,2 +0,0 @@ -dofile 'interpreters/luabase.lua' -return MakeLuaInterpreter() diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb52.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb52.lua deleted file mode 100644 index 989afbc..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb52.lua +++ /dev/null @@ -1,2 +0,0 @@ -dofile 'interpreters/luabase.lua' -return MakeLuaInterpreter(5.2, ' 5.2') diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb53.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb53.lua deleted file mode 100644 index 4b08672..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/interpreters/luadeb53.lua +++ /dev/null @@ -1,4 +0,0 @@ -dofile 'interpreters/luabase.lua' -local interpreter = MakeLuaInterpreter(5.3, ' 5.3') -interpreter.skipcompile = true -return interpreter diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/copas/copas.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/copas/copas.lua deleted file mode 100644 index dd68591..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/copas/copas.lua +++ /dev/null @@ -1,636 +0,0 @@ -------------------------------------------------------------------------------- --- Copas - Coroutine Oriented Portable Asynchronous Services --- --- A dispatcher based on coroutines that can be used by TCP/IP servers. --- Uses LuaSocket as the interface with the TCP/IP stack. --- --- Authors: Andre Carregal, Javier Guerra, and Fabio Mascarenhas --- Contributors: Diego Nehab, Mike Pall, David Burgess, Leonardo Godinho, --- Thomas Harning Jr., and Gary NG --- --- Copyright 2005 - Kepler Project (www.keplerproject.org) --- --- $Id: copas.lua,v 1.37 2009/04/07 22:09:52 carregal Exp $ -------------------------------------------------------------------------------- - -if package.loaded["socket.http"] then - error("you must require copas before require'ing socket.http") -end - -local socket = require "socket" -local gettime = socket.gettime -local coxpcall = require "coxpcall" - -local WATCH_DOG_TIMEOUT = 120 -local UDP_DATAGRAM_MAX = 8192 - --- Redefines LuaSocket functions with coroutine safe versions --- (this allows the use of socket.http from within copas) -local function statusHandler(status, ...) - if status then return ... end - local err = (...) - if type(err) == "table" then - return nil, err[1] - else - error(err) - end -end - -function socket.protect(func) - return function (...) - return statusHandler(coxpcall.pcall(func, ...)) - end -end - -function socket.newtry(finalizer) - return function (...) - local status = (...) - if not status then - coxpcall.pcall(finalizer, select(2, ...)) - error({ (select(2, ...)) }, 0) - end - return ... - end -end - --- end of LuaSocket redefinitions - -local copas = {} - --- Meta information is public even if beginning with an "_" -copas._COPYRIGHT = "Copyright (C) 2005-2010 Kepler Project" -copas._DESCRIPTION = "Coroutine Oriented Portable Asynchronous Services" -copas._VERSION = "Copas 1.2.1" - --- Close the socket associated with the current connection after the handler finishes -copas.autoclose = true - -------------------------------------------------------------------------------- --- Simple set implementation based on LuaSocket's tinyirc.lua example --- adds a FIFO queue for each value in the set -------------------------------------------------------------------------------- -local function newset() - local reverse = {} - local set = {} - local q = {} - setmetatable(set, { __index = { - insert = function(set, value) - if not reverse[value] then - set[#set + 1] = value - reverse[value] = #set - end - end, - - remove = function(set, value) - local index = reverse[value] - if index then - reverse[value] = nil - local top = set[#set] - set[#set] = nil - if top ~= value then - reverse[top] = index - set[index] = top - end - end - end, - - push = function (set, key, itm) - local qKey = q[key] - if qKey == nil then - q[key] = {itm} - else - qKey[#qKey + 1] = itm - end - end, - - pop = function (set, key) - local t = q[key] - if t ~= nil then - local ret = table.remove (t, 1) - if t[1] == nil then - q[key] = nil - end - return ret - end - end - }}) - return set -end - -local fnil = function()end -local _sleeping = { - times = {}, -- list with wake-up times - cos = {}, -- list with coroutines, index matches the 'times' list - lethargy = {}, -- list of coroutines sleeping without a wakeup time - - insert = fnil, - remove = fnil, - push = function(self, sleeptime, co) - if not co then return end - if sleeptime<0 then - --sleep until explicit wakeup through copas.wakeup - self.lethargy[co] = true - return - else - sleeptime = gettime() + sleeptime - end - local t, c = self.times, self.cos - local i, cou = 1, #t - --TODO: do a binary search - while i<=cou and t[i]<=sleeptime do i=i+1 end - table.insert(t, i, sleeptime) - table.insert(c, i, co) - end, - getnext = function(self) -- returns delay until next sleep expires, or nil if there is none - local t = self.times - local delay = t[1] and t[1] - gettime() or nil - - return delay and math.max(delay, 0) or nil - end, - -- find the thread that should wake up to the time - pop = function(self, time) - local t, c = self.times, self.cos - if #t==0 or time 90) then - _writing_log[client] = gettime() - coroutine.yield(client, _writing) - end - if s or err ~= "timeout" then - _writing_log[client] = nil - return s, err,lastIndex - end - _writing_log[client] = gettime() - coroutine.yield(client, _writing) - until false -end - --- sends data to a client over UDP. Not available for TCP. --- (this is a copy of send() method, adapted for sendto() use) -function copas.sendto(client, data, ip, port) - local s, err,sent - - repeat - s, err = client:sendto(data, ip, port) - -- adds extra corrotine swap - -- garantees that high throuput dont take other threads to starvation - if (math.random(100) > 90) then - _writing_log[client] = gettime() - coroutine.yield(client, _writing) - end - if s or err ~= "timeout" then - _writing_log[client] = nil - return s, err - end - _writing_log[client] = gettime() - coroutine.yield(client, _writing) - until false -end - --- waits until connection is completed -function copas.connect(skt, host, port) - skt:settimeout(0) - local ret, err - repeat - ret, err = skt:connect (host, port) - if ret or err ~= "timeout" then - _writing_log[skt] = nil - return ret, err - end - _writing_log[skt] = gettime() - coroutine.yield(skt, _writing) - until false - return ret, err -end - --- flushes a client write buffer (deprecated) -function copas.flush(client) -end - --- wraps a TCP socket to use Copas methods (send, receive, flush and settimeout) -local _skt_mt = {__index = { - send = function (self, data, from, to) - return copas.send (self.socket, data, from, to) - end, - - receive = function (self, pattern, prefix) - if (self.timeout==0) then - return copas.receivePartial(self.socket, pattern, prefix) - end - return copas.receive(self.socket, pattern, prefix) - end, - - flush = function (self) - return copas.flush(self.socket) - end, - - settimeout = function (self,time) - self.timeout=time - return true - end, - - skip = function(self, ...) return self.socket:skip(...) end, - - close = function(self, ...) return self.socket:close(...) end, - }} - --- wraps a UDP socket, copy of TCP one adapted for UDP. --- Mainly adds sendto() and receivefrom() -local _skt_mt_udp = {__index = { - send = function (self, data) - return copas.send (self.socket, data) - end, - - sendto = function (self, data, ip, port) - return copas.sendto (self.socket, data, ip, port) - end, - - receive = function (self, size) - return copas.receive (self.socket, (size or UDP_DATAGRAM_MAX)) - end, - - receivefrom = function (self, size) - return copas.receivefrom (self.socket, (size or UDP_DATAGRAM_MAX)) - end, - - flush = function (self) - return copas.flush (self.socket) - end, - - settimeout = function (self,time) - self.timeout=time - return true - end, - }} - -function copas.wrap (skt) - if string.sub(tostring(skt),1,3) == "udp" then - return setmetatable ({socket = skt}, _skt_mt_udp) - else - return setmetatable ({socket = skt}, _skt_mt) - end -end - --------------------------------------------------- --- Error handling --------------------------------------------------- - -local _errhandlers = {} -- error handler per coroutine - -function copas.setErrorHandler (err) - local co = coroutine.running() - if co then - _errhandlers [co] = err - end -end - -local function _deferror (msg, co, skt) - print (msg, co, skt) -end - -------------------------------------------------------------------------------- --- Thread handling -------------------------------------------------------------------------------- - -local function _doTick (co, skt, ...) - if not co then return end - - local ok, res, new_q = coroutine.resume(co, skt, ...) - - if ok and res and new_q then - new_q:insert (res) - new_q:push (res, co) - else - if not ok then coxpcall.pcall (_errhandlers [co] or _deferror, res, co, skt) end - if skt and copas.autoclose then skt:close() end - _errhandlers [co] = nil - end -end - --- accepts a connection on socket input -local function _accept(input, handler) - local client = input:accept() - if client then - client:settimeout(0) - local co = coroutine.create(handler) - _doTick (co, client) - --_reading:insert(client) - end - return client -end - --- handle threads on a queue -local function _tickRead (skt) - _doTick (_reading:pop (skt), skt) -end - -local function _tickWrite (skt) - _doTick (_writing:pop (skt), skt) -end - -------------------------------------------------------------------------------- --- Adds a server/handler pair to Copas dispatcher -------------------------------------------------------------------------------- -local function addTCPserver(server, handler, timeout) - server:settimeout(timeout or 0.1) - _servers[server] = handler - _reading:insert(server) -end - -local function addUDPserver(server, handler, timeout) - server:settimeout(timeout or 0) - local co = coroutine.create(handler) - _reading:insert(server) - _doTick (co, server) -end - -function copas.addserver(server, handler, timeout) - if string.sub(tostring(server),1,3) == "udp" then - addUDPserver(server, handler, timeout) - else - addTCPserver(server, handler, timeout) - end -end - -function copas.removeserver(server) - _servers[server] = nil - _reading:remove(server) - return server:close() -end - -------------------------------------------------------------------------------- --- Adds an new courotine thread to Copas dispatcher -------------------------------------------------------------------------------- -function copas.addthread(thread, ...) - if type(thread) ~= "thread" then - thread = coroutine.create(thread) - end - _doTick (thread, nil, ...) - return thread -end - -------------------------------------------------------------------------------- --- tasks registering -------------------------------------------------------------------------------- - -local _tasks = {} - -local function addtaskRead (tsk) - -- lets tasks call the default _tick() - tsk.def_tick = _tickRead - - _tasks [tsk] = true -end - -local function addtaskWrite (tsk) - -- lets tasks call the default _tick() - tsk.def_tick = _tickWrite - - _tasks [tsk] = true -end - -local function tasks () - return next, _tasks -end - -------------------------------------------------------------------------------- --- main tasks: manage readable and writable socket sets -------------------------------------------------------------------------------- --- a task to check ready to read events -local _readable_t = { - events = function(self) - local i = 0 - return function () - i = i + 1 - return self._evs [i] - end - end, - - tick = function (self, input) - local handler = _servers[input] - if handler then - input = _accept(input, handler) - else - _reading:remove (input) - self.def_tick (input) - end - end -} - -addtaskRead (_readable_t) - - --- a task to check ready to write events -local _writable_t = { - events = function (self) - local i = 0 - return function () - i = i + 1 - return self._evs [i] - end - end, - - tick = function (self, output) - _writing:remove (output) - self.def_tick (output) - end -} - -addtaskWrite (_writable_t) --- ---sleeping threads task -local _sleeping_t = { - tick = function (self, time, ...) - _doTick(_sleeping:pop(time), ...) - end -} - --- yields the current coroutine and wakes it after 'sleeptime' seconds. --- If sleeptime<0 then it sleeps until explicitly woken up using 'wakeup' -function copas.sleep(sleeptime) - coroutine.yield((sleeptime or 0), _sleeping) -end - --- Wakes up a sleeping coroutine 'co'. -function copas.wakeup(co) - _sleeping:wakeup(co) -end - -local last_cleansing = 0 - -------------------------------------------------------------------------------- --- Checks for reads and writes on sockets -------------------------------------------------------------------------------- -local function _select (timeout) - local err - local now = gettime() - local duration = function(t2, t1) return t2-t1 end - - _readable_t._evs, _writable_t._evs, err = socket.select(_reading, _writing, timeout) - local r_evs, w_evs = _readable_t._evs, _writable_t._evs - - if duration(now, last_cleansing) > WATCH_DOG_TIMEOUT then - last_cleansing = now - for k,v in pairs(_reading_log) do - if not r_evs[k] and duration(now, v) > WATCH_DOG_TIMEOUT then - _reading_log[k] = nil - r_evs[#r_evs + 1] = k - r_evs[k] = #r_evs - end - end - - for k,v in pairs(_writing_log) do - if not w_evs[k] and duration(now, v) > WATCH_DOG_TIMEOUT then - _writing_log[k] = nil - w_evs[#w_evs + 1] = k - w_evs[k] = #w_evs - end - end - end - - if err == "timeout" and #r_evs + #w_evs > 0 then - return nil - else - return err - end -end - - -------------------------------------------------------------------------------- --- Dispatcher loop step. --- Listen to client requests and handles them --- Returns false if no data was handled (timeout), or true if there was data --- handled (or nil + error message) -------------------------------------------------------------------------------- -function copas.step(timeout) - _sleeping_t:tick(gettime()) - - -- Need to wake up the select call it time for the next sleeping event - local nextwait = _sleeping:getnext() - if nextwait then - timeout = timeout and math.min(nextwait, timeout) or nextwait - end - - local err = _select (timeout) - if err == "timeout" then return false end - - if err then - error(err) - end - - for tsk in tasks() do - for ev in tsk:events() do - tsk:tick (ev) - end - end - return true -end - -------------------------------------------------------------------------------- --- Dispatcher endless loop. --- Listen to client requests and handles them forever -------------------------------------------------------------------------------- -function copas.loop(timeout) - while true do - copas.step(timeout) - end -end - -return copas diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/coxpcall/coxpcall.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/coxpcall/coxpcall.lua deleted file mode 100644 index c34bb72..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/coxpcall/coxpcall.lua +++ /dev/null @@ -1,68 +0,0 @@ -------------------------------------------------------------------------------- --- Coroutine safe xpcall and pcall versions --- --- Encapsulates the protected calls with a coroutine based loop, so errors can --- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines --- yielding inside the call to pcall or xpcall. --- --- Authors: Roberto Ierusalimschy and Andre Carregal --- Contributors: Thomas Harning Jr., Ignacio Burgueo, Fabio Mascarenhas --- --- Copyright 2005 - Kepler Project (www.keplerproject.org) --- --- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $ -------------------------------------------------------------------------------- - --- Lua 5.2 makes this module a no-op -if _VERSION == "Lua 5.2" then - copcall = pcall - coxpcall = xpcall - return { pcall = pcall, xpcall = xpcall } -end - -------------------------------------------------------------------------------- --- Implements xpcall with coroutines -------------------------------------------------------------------------------- -local performResume, handleReturnValue -local oldpcall, oldxpcall = pcall, xpcall -local pack = table.pack or function(...) return {n = select("#", ...), ...} end -local unpack = table.unpack or unpack - -function handleReturnValue(err, co, status, ...) - if not status then - return false, err(debug.traceback(co, (...)), ...) - end - if coroutine.status(co) == 'suspended' then - return performResume(err, co, coroutine.yield(...)) - else - return true, ... - end -end - -function performResume(err, co, ...) - return handleReturnValue(err, co, coroutine.resume(co, ...)) -end - -function coxpcall(f, err, ...) - local res, co = oldpcall(coroutine.create, f) - if not res then - local params = pack(...) - local newf = function() return f(unpack(params, 1, params.n)) end - co = coroutine.create(newf) - end - return performResume(err, co, ...) -end - -------------------------------------------------------------------------------- --- Implements pcall with coroutines -------------------------------------------------------------------------------- - -local function id(trace, ...) - return ... -end - -function copcall(f, ...) - return coxpcall(f, id, ...) -end - -return { pcall = copcall, xpcall = coxpcall } \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/config.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/config.lua deleted file mode 100644 index 3139750..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/config.lua +++ /dev/null @@ -1,112 +0,0 @@ --- Luadist configuration - -module ("dist.config", package.seeall) - -local sys = require "dist.sys" -local utils = require "dist.utils" -local win = (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')) - and not (os.getenv('OSTYPE') or ''):match('cygwin') -- exclude cygwin - --- System information ------------------------------------------------ -version = "0.2.7" -- Current LuaDist version --- set initial architecture as it's important for path separators -arch = win and "Windows" or "Linux" -- Host architecture -type = "x86" -- Host type - --- Directories ------------------------------------------------------- -root_dir = os.getenv("DIST_ROOT") or utils.get_luadist_location() or sys.path_separator() -temp_dir = "tmp" -cache_dir = sys.make_path(temp_dir, "cache") -distinfos_dir = sys.make_path("share", "luadist-git", "dists") -test_dir = sys.make_path("share", "luadist-git", "test") - --- Files ------------------------------------------------------------- -manifest_file = sys.make_path(cache_dir, ".gitmodules") -dep_cache_file = sys.make_path(cache_dir, ".depcache") -log_file = sys.make_path(temp_dir, "luadist.log") -cache_file = "" - --- Repositories ------------------------------------------------------ -repos = { - "git://github.com/LuaDist/Repository.git", -} - -upload_url = "git@github.com:LuaDist" -- must not contain trailing '/' - --- Settings ---------------------------------------------------------- -debug = false -- Use debug mode. -verbose = false -- Print verbose output. -simulate = false -- Only simulate installation of packages. -binary = true -- Use binary version of modules. -source = true -- Use source version of modules. -test = false -- Run CTest before install. - -cache = true -- Use cache. -cache_timeout = 3 * 60 * 60 -- Cache timeout in seconds. - -dep_cache = true -- Use cache for dependency information (tree functionality). - --- Components (of modules) that will be installed. -components = { - "Runtime", "Library", "Header", "Data", "Documentation", "Example", "Test", "Other", "Unspecified" -} - --- Available log levels are: DEBUG, INFO, WARN, ERROR, FATAL (see dist.logger for more information). -print_log_level = "WARN" -- Minimum level for log messages to be printed (nil to disable). -write_log_level = "INFO" -- Minimum level for log messages to be logged (nil to disable). - - --- CMake variables --------------------------------------------------- -variables = { - --- Install defaults - INSTALL_BIN = "bin", - INSTALL_LIB = "lib", - INSTALL_INC = "include", - INSTALL_ETC = "etc", - INSTALL_LMOD = "lib/lua", - INSTALL_CMOD = "lib/lua", - - --- LuaDist specific variables - DIST_VERSION = version, - DIST_ARCH = arch, - DIST_TYPE = type, - - -- CMake specific setup - CMAKE_GENERATOR = win and "MinGW Makefiles" or "Unix Makefiles", - CMAKE_BUILD_TYPE = "MinSizeRel", - - -- RPath functionality - CMAKE_SKIP_BUILD_RPATH = "FALSE", - CMAKE_BUILD_WITH_INSTALL_RPATH = "FALSE", - CMAKE_INSTALL_RPATH = "$ORIGIN/../lib", - CMAKE_INSTALL_RPATH_USE_LINK_PATH = "TRUE", - CMAKE_INSTALL_NAME_DIR = "@executable_path/../lib", - - -- OSX specific - CMAKE_OSX_ARCHITECTURES = "", -} - --- Building ---------------------------------------------------------- -cmake = "cmake" -ctest = "ctest" - -cache_command = cmake .. " -C cache.cmake" -build_command = cmake .. " --build . --clean-first" - -install_component_command = " -DCOMPONENT=#COMPONENT# -P cmake_install.cmake" - -test_command = ctest .. " -V ." - -strip_option = " -DCMAKE_INSTALL_DO_STRIP=true" -cache_debug_options = "-DCMAKE_VERBOSE_MAKEFILE=true -DCMAKE_BUILD_TYPE=Debug" -build_debug_options = "" - --- Add -j option to make in case of unix makefiles to speed up builds -if (variables.CMAKE_GENERATOR == "Unix Makefiles") then - build_command = build_command .. " -- -j6" -end - --- Add -j option to make in case of MinGW makefiles to speed up builds -if (variables.CMAKE_GENERATOR == "MinGW Makefiles") then - build_command = "set SHELL=cmd.exe && " .. build_command .. " -- -j" -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/constraints.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/constraints.lua deleted file mode 100644 index 1b5cfec..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/constraints.lua +++ /dev/null @@ -1,271 +0,0 @@ --- Note: the code of this module is borrowed from the original LuaDist project - - - ---- LuaDist version constraints functions --- Peter Drahoš, LuaDist Project, 2010 --- Original Code borrowed from LuaRocks Project - ---- Version constraints handling functions. --- Dependencies are represented in LuaDist through strings with --- a dist name followed by a comma-separated list of constraints. --- Each constraint consists of an operator and a version number. --- In this string format, version numbers are represented as --- naturally as possible, like they are used by upstream projects --- (e.g. "2.0beta3"). Internally, LuaDist converts them to a purely --- numeric representation, allowing comparison following some --- "common sense" heuristics. The precise specification of the --- comparison criteria is the source code of this module, but the --- test/test_deps.lua file included with LuaDist provides some --- insights on what these criteria are. - -module ("dist.constraints", package.seeall) - - -local operators = { - ["=="] = "==", - ["~="] = "~=", - [">"] = ">", - ["<"] = "<", - [">="] = ">=", - ["<="] = "<=", - ["~>"] = "~>", - -- plus some convenience translations - [""] = "==", - ["-"] = "==", - ["="] = "==", - ["!="] = "~=" -} - -local deltas = { - scm = -100, - rc = -1000, - pre = -10000, - beta = -100000, - alpha = -1000000, - work = -10000000, -} - -local version_mt = { - --- Equality comparison for versions. - -- All version numbers must be equal. - -- If both versions have revision numbers, they must be equal; - -- otherwise the revision number is ignored. - -- @param v1 table: version table to compare. - -- @param v2 table: version table to compare. - -- @return boolean: true if they are considered equivalent. - __eq = function(v1, v2) - if #v1 ~= #v2 then - return false - end - for i = 1, #v1 do - if v1[i] ~= v2[i] then - return false - end - end - if v1.revision and v2.revision then - return (v1.revision == v2.revision) - end - return true - end, - --- Size comparison for versions. - -- All version numbers are compared. - -- If both versions have revision numbers, they are compared; - -- otherwise the revision number is ignored. - -- @param v1 table: version table to compare. - -- @param v2 table: version table to compare. - -- @return boolean: true if v1 is considered lower than v2. - __lt = function(v1, v2) - for i = 1, math.max(#v1, #v2) do - local v1i, v2i = v1[i] or 0, v2[i] or 0 - if v1i ~= v2i then - return (v1i < v2i) - end - end - if v1.revision and v2.revision then - return (v1.revision < v2.revision) - end - return false - end -} - -local version_cache = {} -setmetatable(version_cache, { - __mode = "kv" -}) - ---- Parse a version string, converting to table format. --- A version table contains all components of the version string --- converted to numeric format, stored in the array part of the table. --- If the version contains a revision, it is stored numerically --- in the 'revision' field. The original string representation of --- the string is preserved in the 'string' field. --- Returned version tables use a metatable --- allowing later comparison through relational operators. --- @param vstring string: A version number in string format. --- @return table or nil: A version table or nil --- if the input string contains invalid characters. -function parseVersion(vstring) - if not vstring then return nil end - assert(type(vstring) == "string") - - local cached = version_cache[vstring] - if cached then - return cached - end - - local version = {} - local i = 1 - - local function add_token(number) - version[i] = version[i] and version[i] + number/100000 or number - i = i + 1 - end - - -- trim leading and trailing spaces - vstring = vstring:match("^%s*(.*)%s*$") - version.string = vstring - -- store revision separately if any - local main, revision = vstring:match("(.*)%-(%d+)$") - if revision then - vstring = main - version.revision = tonumber(revision) - end - while #vstring > 0 do - -- extract a number - local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)") - if token then - add_token(tonumber(token)) - else - -- extract a word - token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)") - if not token then - return nil - end - local last = #version - version[i] = deltas[token] or (token:byte() / 1000) - end - vstring = rest - end - setmetatable(version, version_mt) - version_cache[vstring] = version - return version -end - ---- Utility function to compare version numbers given as strings. --- @param a string: one version. --- @param b string: another version. --- @return boolean: True if a > b. -function compareVersions(a, b) - return parseVersion(a) > parseVersion(b) -end - ---- Consumes a constraint from a string, converting it to table format. --- For example, a string ">= 1.0, > 2.0" is converted to a table in the --- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned --- back to the caller. --- @param input string: A list of constraints in string format. --- @return (table, string) or nil: A table representing the same --- constraints and the string with the unused input, or nil if the --- input string is invalid. -local function parseConstraint(input) - assert(type(input) == "string") - - local op, version, rest = input:match("^([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)") - op = operators[op] - version = parseVersion(version) - if not op or not version then return nil end - return { op = op, version = version }, rest -end - ---- Convert a list of constraints from string to table format. --- For example, a string ">= 1.0, < 2.0" is converted to a table in the format --- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}. --- Version tables use a metatable allowing later comparison through --- relational operators. --- @param input string: A list of constraints in string format. --- @return table or nil: A table representing the same constraints, --- or nil if the input string is invalid. -function parseConstraints(input) - assert(type(input) == "string") - - local constraints, constraint = {}, nil - while #input > 0 do - constraint, input = parseConstraint(input) - if constraint then - table.insert(constraints, constraint) - else - return nil - end - end - return constraints -end - ---- A more lenient check for equivalence between versions. --- This returns true if the requested components of a version --- match and ignore the ones that were not given. For example, --- when requesting "2", then "2", "2.1", "2.3.5-9"... all match. --- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2" --- doesn't. --- @param version string or table: Version to be tested; may be --- in string format or already parsed into a table. --- @param requested string or table: Version requested; may be --- in string format or already parsed into a table. --- @return boolean: True if the tested version matches the requested --- version, false otherwise. -local function partialMatch(version, requested) - assert(type(version) == "string" or type(version) == "table") - assert(type(requested) == "string" or type(version) == "table") - - if type(version) ~= "table" then version = parseVersion(version) end - if type(requested) ~= "table" then requested = parseVersion(requested) end - if not version or not requested then return false end - - for i = 1, #requested do - if requested[i] ~= version[i] then return false end - end - if requested.revision then - return requested.revision == version.revision - end - return true -end - ---- Check if a version satisfies a set of constraints. --- @param version table: A version in table format --- @param constraints table: An array of constraints in table format. --- @return boolean: True if version satisfies all constraints, --- false otherwise. -function matchConstraints(version, constraints) - assert(type(version) == "table") - assert(type(constraints) == "table") - local ok = true - setmetatable(version, version_mt) - for _, constr in pairs(constraints) do - local constr_version = constr.version - setmetatable(constr.version, version_mt) - if constr.op == "==" then ok = version == constr_version - elseif constr.op == "~=" then ok = version ~= constr_version - elseif constr.op == ">" then ok = version > constr_version - elseif constr.op == "<" then ok = version < constr_version - elseif constr.op == ">=" then ok = version >= constr_version - elseif constr.op == "<=" then ok = version <= constr_version - elseif constr.op == "~>" then ok = partialMatch(version, constr_version) - end - if not ok then break end - end - return ok -end - ---- Check if a version string is satisfied by a constraint string. --- @param version string: A version in string format --- @param constraints string: Constraints in string format. --- @return boolean: True if version satisfies all constraints, --- false otherwise. -function constraint_satisfied(version, constraints) - local const = parseConstraints(constraints) - local ver = parseVersion(version) - if const and ver then - return matchConstraints(ver, const) - end - return nil, "Error parsing versions." -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/depends.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/depends.lua deleted file mode 100644 index 2a6b7f0..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/depends.lua +++ /dev/null @@ -1,770 +0,0 @@ --- Utility functions for dependencies - -module ("dist.depends", package.seeall) - -local cfg = require "dist.config" -local mf = require "dist.manifest" -local sys = require "dist.sys" -local const = require "dist.constraints" -local utils = require "dist.utils" -local package = require "dist.package" - --- Return all packages with specified names from manifest. --- Names can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.). -function find_packages(package_names, manifest) - if type(package_names) == "string" then package_names = {package_names} end - manifest = manifest or mf.get_manifest() - assert(type(package_names) == "table", "depends.find_packages: Argument 'package_names' is not a table or string.") - assert(type(manifest) == "table", "depends.find_packages: Argument 'manifest' is not a table.") - - local packages_found = {} - -- find matching packages in manifest - for _, pkg_to_find in pairs(package_names) do - local pkg_name, pkg_constraint = split_name_constraint(pkg_to_find) - pkg_name = utils.escape_magic(pkg_name):gsub("%%%*",".*") - for _, repo_pkg in pairs(manifest) do - if string.match(repo_pkg.name, "^" .. pkg_name .. "$") and (not pkg_constraint or satisfies_constraint(repo_pkg.version, pkg_constraint)) then - table.insert(packages_found, repo_pkg) - end - end - end - return packages_found -end - --- Return manifest consisting of packages installed in specified deploy_dir directory -function get_installed(deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(deploy_dir) == "string", "depends.get_installed: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local distinfos_path = sys.make_path(deploy_dir, cfg.distinfos_dir) - local manifest = {} - - if not sys.is_dir(distinfos_path) then return {} end - - -- from all directories of packages installed in deploy_dir - for dir in sys.get_directory(distinfos_path) do - - if dir ~= "." and dir ~= ".." and sys.is_dir(sys.make_path(distinfos_path, dir)) then - local pkg_dist_dir = sys.make_path(distinfos_path, dir) - - -- load the dist.info file - for file in sys.get_directory(pkg_dist_dir) do - local pkg_dist_file = sys.make_path(pkg_dist_dir, file) - - if sys.is_file(pkg_dist_file) then - table.insert(manifest, mf.load_distinfo(pkg_dist_file)) - end - end - - end - - end - return manifest -end - --- If 'pkg.selected' == true then returns 'selected' else 'installed'. --- Used in error messages. -local function selected_or_installed(pkg) - assert(type(pkg) == "table", "depends.selected_or_installed: Argument 'pkg' is not a table.") - if pkg.selected == true then - return "selected" - else - return "installed" - end -end - --- Return whether the 'package_name' is installed according to the the manifest 'installed_pkgs' --- If optional 'version_wanted' constraint is specified, then installed packages must --- also satisfy specified version constraint. --- If package is installed but doesn't satisfy version constraint, error message --- is returned as the second value. -function is_installed(package_name, installed_pkgs, version_wanted) - assert(type(package_name) == "string", "depends.is_installed: Argument 'package_name' is not a string.") - assert(type(installed_pkgs) == "table", "depends.is_installed: Argument 'installed_pkgs' is not a table.") - assert(type(version_wanted) == "string" or type(version_wanted) == "nil", "depends.is_installed: Argument 'version_wanted' is not a string or nil.") - - local pkg_is_installed, err = false, nil - - for _, installed_pkg in pairs(installed_pkgs) do - - -- check if package_name is in installed - if package_name == installed_pkg.name then - - -- check if package is installed in satisfying version - if not version_wanted or satisfies_constraint(installed_pkg.version, version_wanted) then - pkg_is_installed = true - break - else - err = "Package '" .. package_name .. (version_wanted and " " .. version_wanted or "") .. "' needed, but " .. selected_or_installed(installed_pkg) .. " at version '" .. installed_pkg.version .. "'." - break - end - end - - end - return pkg_is_installed, err -end - --- Check whether the package 'pkg' conflicts with 'installed_pkg' and return --- false or error message. -local function packages_conflicts(pkg, installed_pkg) - assert(type(pkg) == "table", "depends.packages_conflicts: Argument 'pkg' is not a table.") - assert(type(installed_pkg) == "table", "depends.packages_conflicts: Argument 'installed_pkg' is not a table.") - - -- check if pkg doesn't provide an already installed_pkg - if pkg.provides then - -- for all of pkg's provides - for _, provided_pkg in pairs(get_provides(pkg)) do - if provided_pkg.name == installed_pkg.name then - return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' provides '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' but package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' is already " .. selected_or_installed(installed_pkg) .. "." - end - end - end - - -- check for conflicts of package to install with installed package - if pkg.conflicts then - for _, conflict in pairs (pkg.conflicts) do - if conflict == installed_pkg.name then - return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' conflicts with already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "'." - end - end - end - - -- check for conflicts of installed package with package to install - if installed_pkg.conflicts then - - -- direct conflicts with 'pkg' - for _, conflict in pairs (installed_pkg.conflicts) do - if conflict == pkg.name then - return "Already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'." - end - end - - -- conflicts with 'provides' of 'pkg' (packages provided by package to install) - if pkg.provides then - for _, conflict in pairs (installed_pkg.conflicts) do - -- for all of pkg's provides - for _, provided_pkg in pairs(get_provides(pkg)) do - if conflict == provided_pkg.name then - return "Already '" .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' provided by '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'." - end - end - end - end - end - - -- no conflicts found - return false -end - --- Return table of package dependencies 'depends' with OS specific dependencies extracted. --- --- OS specific dependencies are stored in a subtable with 'arch' as a key. --- E.g. this table containing OS specific dependencies: --- depends = { --- "lua~>5.1", --- "luadist-git>=0.1", --- Linux = { --- "iup>=3.6", --- "wxlua>=2.8.10.0", --- }, --- Windows = { --- "luagd>=2.0.33r2", --- "luacom>=1.4.1", --- }, --- } --- --- ...will be on the 'Linux' architecture (determined by cfg.arch) converted into: --- depends = { --- "lua~>5.1", --- "luadist-git>=0.1", --- "iup>=3.6", --- "wxlua>=2.8.10.0", --- } -function extract_os_specific_depends(depends) - assert(type(depends) == "table", "depends.extract_os_specific_depends: Argument 'depends' is not a table.") - local extracted = {} - for k, depend in pairs(depends) do - -- if 'depend' is a table, then it must be a table of OS specific - -- dependencies, so extract it if it's for this architecture - if type(depend) == "table" then - if k == cfg.arch then - for _, os_specific_depend in pairs(depend) do - table.insert(extracted, os_specific_depend) - end - end - else - table.insert(extracted, depend) - end - end - return extracted -end - --- Return all packages needed in order to install package 'pkg' --- and with specified 'installed' packages in the system using 'manifest'. --- 'pkg' can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.). --- --- This function also downloads packages to get information about their dependencies. --- Directory where the package was downloaded is stored in 'download_dir' attribute --- of that package in the table of packages returned by this function. --- --- Optional argument 'dependency_manifest' is a table of dependencies examined --- from previous installations etc. It can be used to speed-up the dependency --- resolving procedure for example. --- --- When optional 'force_no_download' parameter is set to true, then information --- about packages won't be downloaded during dependency resolving, assuming that --- entries in the provided manifest are already complete. --- --- When optional 'suppress_printing' parameter is set to true, then messages --- for the user won't be printed during dependency resolving. --- --- Optional argument 'deploy_dir' is used just as a temporary place to place --- the downloaded packages into. --- --- 'dependency_parents' is table of all packages encountered so far when resolving dependencies --- and is used to detect and deal with circular dependencies. Leave it 'nil' --- and it will do its job just fine :-). --- --- 'tmp_installed' is internal table used in recursion and should be left 'nil' when --- calling this function from other context. It is used for passing the changes --- in installed packages between the recursive calls of this function. --- --- TODO: refactor this spaghetti code! -local function get_packages_to_install(pkg, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed) - manifest = manifest or mf.get_manifest() - dependency_manifest = dependency_manifest or {} - force_no_download = force_no_download or false - suppress_printing = suppress_printing or false - deploy_dir = deploy_dir or cfg.root_dir - dependency_parents = dependency_parents or {} - - -- set helper table 'tmp_installed' - tmp_installed = tmp_installed or utils.deepcopy(installed) - - assert(type(pkg) == "string", "depends.get_packages_to_install: Argument 'pkg' is not a string.") - assert(type(installed) == "table", "depends.get_packages_to_install: Argument 'installed' is not a table.") - assert(type(manifest) == "table", "depends.get_packages_to_install: Argument 'manifest' is not a table.") - assert(type(dependency_manifest) == "table", "depends.get_packages_to_install: Argument 'dependency_manifest' is not a table.") - assert(type(force_no_download) == "boolean", "depends.get_packages_to_install: Argument 'force_no_download' is not a boolean.") - assert(type(suppress_printing) == "boolean", "depends.get_packages_to_install: Argument 'suppress_printing' is not a boolean.") - assert(type(deploy_dir) == "string", "depends.get_packages_to_install: Argument 'deploy_dir' is not a string.") - assert(type(dependency_parents) == "table", "depends.get_packages_to_install: Argument 'dependency_parents' is not a table.") - assert(type(tmp_installed) == "table", "depends.get_packages_to_install: Argument 'tmp_installed' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - --[[ for future debugging: - print('resolving: '.. pkg) - print(' installed: ', utils.table_tostring(installed)) - print(' tmp_installed: ', utils.table_tostring(tmp_installed)) - --]] - - -- check if package is already installed - local pkg_name, pkg_constraint = split_name_constraint(pkg) - local pkg_is_installed, err = is_installed(pkg_name, tmp_installed, pkg_constraint) - if pkg_is_installed then return {} end - if err then return nil, err end - - -- table of packages needed to be installed (will be returned) - local to_install = {} - - -- find out available versions of 'pkg' and insert them into manifest - if not force_no_download then - local versions, err = package.retrieve_versions(pkg, manifest, suppress_printing) - if not versions then return nil, err end - for _, version in pairs(versions) do - table.insert(manifest, version) - end - end - - -- find candidates & sort them - local candidates_to_install = find_packages(pkg, manifest) - if #candidates_to_install == 0 then - return nil, "No suitable candidate for '" .. pkg .. "' found." - end - candidates_to_install = sort_by_versions(candidates_to_install) - - for _, pkg in pairs(candidates_to_install) do - - --[[ for future debugging: - print(' candidate: '.. pkg.name..'-'..pkg.version) - print(' installed: ', utils.table_tostring(installed)) - print(' tmp_installed: ', utils.table_tostring(tmp_installed)) - print(' to_install: ', utils.table_tostring(to_install)) - print(' -is installed: ', is_installed(pkg.name, tmp_installed, pkg_constraint)) - --]] - - -- if there's an error from the previous candidate, print the reason for trying another one - if not suppress_printing and err then print(" - trying another candidate due to: " .. err) end - - -- clear the state from the previous candidate - pkg_is_installed, err = false, nil - - -- check whether this package has already been added to 'tmp_installed' by another of its candidates - pkg_is_installed, err = is_installed(pkg.name, tmp_installed, pkg_constraint) - if pkg_is_installed then break end - - -- preserve information about the 'scm' version, because pkg.version - -- will be rewritten by information taken from pkg's dist.info file - local was_scm_version = (pkg.version == "scm") - - -- Try to obtain cached dependency information from the dependency manifest - if dependency_manifest[pkg.name .. "-" .. pkg.version] and cfg.dep_cache then - pkg = dependency_manifest[pkg.name .. "-" .. pkg.version] - else - -- download info about the package if not already downloaded and downloading not prohibited - if not (pkg.download_dir or force_no_download) then - local path_or_err - pkg, path_or_err = package.retrieve_pkg_info(pkg, deploy_dir, suppress_printing) - if not pkg then - err = "Error when resolving dependencies: " .. path_or_err - else - -- set path to downloaded package - used to indicate that the - -- package was already downloaded, to delete unused but downloaded - -- packages and also to install choosen packages - pkg.download_dir = path_or_err - end - end - end - - if pkg and was_scm_version then pkg.was_scm_version = true end - - -- check arch & type - if not err then - if not (pkg.arch == "Universal" or pkg.arch == cfg.arch) or - not (pkg.type == "all" or pkg.type == "source" or pkg.type == cfg.type) then - err = "Package '" .. pkg_full_name(pkg.name, pkg.version) .. "' doesn't have required arch and type." - end - end - - -- checks for conflicts with other installed (or previously selected) packages - if not err then - for _, installed_pkg in pairs(tmp_installed) do - err = packages_conflicts(pkg, installed_pkg) - if err then break end - end - end - - -- if pkg passed all of the above tests - if not err then - - -- check if pkg's dependencies are satisfied - if pkg.depends then - - -- insert pkg into the stack of circular dependencies detection - table.insert(dependency_parents, pkg.name) - - -- extract all OS specific dependencies of pkg - pkg.depends = extract_os_specific_depends(pkg.depends) - - -- for all dependencies of pkg - for _, depend in pairs(pkg.depends) do - local dep_name = split_name_constraint(depend) - - -- detect circular dependencies using 'dependency_parents' - local is_circular_dependency = false - for _, parent in pairs(dependency_parents) do - if dep_name == parent then - is_circular_dependency = true - break - end - end - - -- if circular dependencies not detected - if not is_circular_dependency then - - -- recursively call this function on the candidates of this pkg's dependency - local depends_to_install, dep_err = get_packages_to_install(depend, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed) - - -- if any suitable dependency packages were found, insert them to the 'to_install' table - if depends_to_install then - for _, depend_to_install in pairs(depends_to_install) do - - -- add some meta information - if not depend_to_install.selected_by then - depend_to_install.selected_by = pkg.name .. "-" .. pkg.version - end - - table.insert(to_install, depend_to_install) - table.insert(tmp_installed, depend_to_install) - table.insert(installed, depend_to_install) - end - else - err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': " .. dep_err - break - end - - -- if circular dependencies detected - else - err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': '" .. dep_name .. "' is a circular dependency." - break - end - end - - -- remove last package from the stack of circular dependencies detection - table.remove(dependency_parents) - end - - -- if no error occured - if not err then - -- add pkg and it's provides to the fake table of installed packages, with - -- property 'selected' set, indicating that the package isn't - -- really installed in the system, just selected to be installed (this is used e.g. in error messages) - pkg.selected = true - table.insert(tmp_installed, pkg) - if pkg.provides then - for _, provided_pkg in pairs(get_provides(pkg)) do - provided_pkg.selected = true - table.insert(tmp_installed, provided_pkg) - end - end - -- add pkg to the table of packages to install - table.insert(to_install, pkg) - - -- if some error occured - else - -- delete the downloaded package - if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end - - -- set tables of 'packages to install' and 'installed packages' to their original state - - to_install = {} - tmp_installed = utils.deepcopy(installed) - -- add provided packages to installed ones - for _, installed_pkg in pairs(tmp_installed) do - for _, pkg in pairs(get_provides(installed_pkg)) do - table.insert(tmp_installed, pkg) - end - end - end - - -- if error occured - else - -- delete the downloaded package - if pkg and pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end - - -- if pkg is already installed, skip checking its other candidates - if pkg_is_installed then break end - end - end - - -- if package is not installed and no suitable candidates were found, return the last error - if #to_install == 0 and not pkg_is_installed then - return nil, err - else - return to_install - end -end - --- Resolve dependencies and return all packages needed in order to install --- 'packages' into the system with already 'installed' packages, using 'manifest'. --- Also return the table of the dependencies determined during the process --- as the second return value. --- --- Optional argument 'dependency_manifest' is a table of dependencies examined --- from previous installations etc. It can be used to speed-up the dependency --- resolving procedure for example. --- --- Optional argument 'deploy_dir' is used as a temporary place to place the --- downloaded packages into. --- --- When optional 'force_no_download' parameter is set to true, then information --- about packages won't be downloaded during dependency resolving, assuming that --- entries in manifest are complete. --- --- When optional 'suppress_printing' parameter is set to true, then messages --- for the user won't be printed during dependency resolving. -function get_depends(packages, installed, manifest, dependency_manifest, deploy_dir, force_no_download, suppress_printing) - if not packages then return {} end - manifest = manifest or mf.get_manifest() - dependency_manifest = dependency_manifest or {} - deploy_dir = deploy_dir or cfg.root_dir - force_no_download = force_no_download or false - suppress_printing = suppress_printing or false - if type(packages) == "string" then packages = {packages} end - - assert(type(packages) == "table", "depends.get_depends: Argument 'packages' is not a table or string.") - assert(type(installed) == "table", "depends.get_depends: Argument 'installed' is not a table.") - assert(type(manifest) == "table", "depends.get_depends: Argument 'manifest' is not a table.") - assert(type(dependency_manifest) == "table", "depends.get_depends: Argument 'dependency_manifest' is not a table.") - assert(type(deploy_dir) == "string", "depends.get_depends: Argument 'deploy_dir' is not a string.") - assert(type(force_no_download) == "boolean", "depends.get_depends: Argument 'force_no_download' is not a boolean.") - assert(type(suppress_printing) == "boolean", "depends.get_depends: Argument 'suppress_printing' is not a boolean.") - deploy_dir = sys.abs_path(deploy_dir) - - local tmp_installed = utils.deepcopy(installed) - - -- add provided packages to installed ones - for _, installed_pkg in pairs(tmp_installed) do - for _, pkg in pairs(get_provides(installed_pkg)) do - table.insert(tmp_installed, pkg) - end - end - - -- If 'pkg' contains valid (architecture specific) path separator, - -- it is treated like a path to already downloaded package and - -- we assume that user wants to use this specific version of the - -- module to be installed. Hence, we will add information about - -- this version into the manifest and also remove references to - -- any other versions of this module from the manifest. This will - -- enforce the version of the module required by the user. - for k, pkg in pairs(packages) do - if pkg:find(sys.path_separator()) then - local pkg_dir = sys.abs_path(pkg) - local pkg_info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info")) - if not pkg_info then return nil, err end - - -- add information about location of the package, also to prevent downloading it again - pkg_info.download_dir = pkg_dir - -- mark package to skip deleting its directory after installation - pkg_info.preserve_pkg_dir = true - - -- set default arch/type if not explicitly stated and package is of source type - if package.is_source_type(pkg_dir) then - pkg_info = package.ensure_source_arch_and_type(pkg_info) - elseif not (pkg_info.arch and pkg_info.type) then - return nil, pkg_dir .. ": binary package missing arch or type in 'dist.info'." - end - - -- update manifest - manifest = utils.filter(manifest, function(p) return p.name ~= pkg_info.name and true end) - table.insert(manifest, pkg_info) - - -- update packages to install - pkg = pkg_info.name .. "-" .. pkg_info.version - packages[k] = pkg - end - end - - local to_install = {} - - -- get packages needed to satisfy the dependencies - for _, pkg in pairs(packages) do - - local needed_to_install, err = get_packages_to_install(pkg, tmp_installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir) - - -- if everything's fine - if needed_to_install then - - for _, needed_pkg in pairs(needed_to_install) do - - -- TODO: why not to use 'installed' instead of 'tmp_installed'? - -- It's because provides aren't searched for by find() - -- function inside the update_dependency_manifest(). - dependency_manifest = update_dependency_manifest(needed_pkg, tmp_installed, needed_to_install, dependency_manifest) - - table.insert(to_install, needed_pkg) - table.insert(tmp_installed, needed_pkg) - -- add provides of needed_pkg to installed ones - for _, provided_pkg in pairs(get_provides(needed_pkg)) do - -- copy 'selected' property - provided_pkg.selected = needed_pkg.selected - table.insert(tmp_installed, provided_pkg) - end - end - -- if error occured - else - -- delete already downloaded packages - for _, pkg in pairs(to_install) do - if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end - end - return nil, "Cannot resolve dependencies for '" .. pkg .. "': ".. err - end - end - - return to_install, dependency_manifest -end - --- Return table of packages provided by specified package (from it's 'provides' field) -function get_provides(package) - assert(type(package) == "table", "depends.get_provides: Argument 'package' is not a table.") - if not package.provides then return {} end - - local provided = {} - for _, provided_name in pairs(package.provides) do - local pkg = {} - pkg.name, pkg.version = split_name_constraint(provided_name) - pkg.type = package.type - pkg.arch = package.arch - pkg.provided = package.name .. "-" .. package.version - table.insert(provided, pkg) - end - return provided -end - --- Return package name and version constraint from full package version constraint specification --- E. g.: --- for 'luaexpat-1.2.3' return: 'luaexpat' , '1.2.3' --- for 'luajit >= 1.2' return: 'luajit' , '>=1.2' -function split_name_constraint(version_constraint) - assert(type(version_constraint) == "string", "depends.split_name_constraint: Argument 'version_constraint' is not a string.") - - local split = version_constraint:find("[%s=~<>-]+%d") or version_constraint:find("[%s=~<>-]+scm") - - if split then - return version_constraint:sub(1, split - 1), version_constraint:sub(split):gsub("[%s-]", "") - else - return version_constraint, nil - end -end - --- Return only packages that can be installed on the specified architecture and type -function filter_packages_by_arch_and_type(packages, req_arch, req_type) - assert(type(packages) == "table", "depends.filter_packages_by_arch_and_type: Argument 'packages' is not a table.") - assert(type(req_arch) == "string", "depends.filter_packages_by_arch_and_type: Argument 'req_arch' is not a string.") - assert(type(req_type) == "string", "depends.filter_packages_by_arch_and_type: Argument 'pkg_type' is not a string.") - - return utils.filter(packages, - function (pkg) - return (pkg.arch == "Universal" or pkg.arch == req_arch) and - (pkg.type == "all" or pkg.type == "source" or pkg.type == req_type) - end) -end - --- Return only packages that contain one of the specified strings in their 'name-version'. --- Case is ignored. If no strings are specified, return all the packages. --- Argument 'search_in_desc' specifies if search also in description of packages. -function filter_packages_by_strings(packages, strings, search_in_desc) - if type(strings) == "string" then strings = {strings} end - assert(type(packages) == "table", "depends.filter_packages_by_strings: Argument 'packages' is not a table.") - assert(type(strings) == "table", "depends.filter_packages_by_strings: Argument 'strings' is not a string or table.") - - if #strings ~= 0 then - return utils.filter(packages, - function (pkg) - for _,str in pairs(strings) do - local name = pkg.name .. "-" .. pkg.version - if search_in_desc then - name = name .. " " .. (pkg.desc or "") - end - if string.find(string.lower(name), string.lower(str), 1 ,true) ~= nil then return true end - end - end) - else - return packages - end -end - - --- Return full package name and version string (e.g. 'luajit-2.0'). When version --- is nil or '' then return only name (e.g. 'luajit') and when name is nil or '' --- then return ''. Optional 'was_scm_version' argument is a boolean, --- stating whether the package was originally selected for installation as a 'scm' version. -function pkg_full_name(name, version, was_scm_version) - name = name or "" - version = version or "" - was_scm_version = was_scm_version or false - if type(version) == "number" then version = tostring(version) end - - assert(type(name) == "string", "depends.pkg_full_name: Argument 'name' is not a string.") - assert(type(version) == "string", "depends.pkg_full_name: Argument 'version' is not a string.") - - if was_scm_version then version = version .. " [scm version]" end - - if name == "" then - return "" - else - return name .. ((version ~= "") and "-" .. version or "") - end -end - --- Return table of packages, sorted descendingly by versions (newer ones are moved to the top). -function sort_by_versions(packages) - assert(type(packages) == "table", "depends.sort_by_versions: Argument 'packages' is not a table.") - return utils.sort(packages, function (a, b) return compare_versions(a.version, b.version) end) -end - --- Return table of packages, sorted alphabetically by name and then descendingly by version. -function sort_by_names(packages) - assert(type(packages) == "table", "depends.sort_by_names: Argument 'packages' is not a table.") - return utils.sort(packages, function (a, b) - if a.name == b.name then - return compare_versions(a.version, b.version) - else - return a.name < b.name - end - end) -end - --- Return if version satisfies the specified constraint -function satisfies_constraint(version, constraint) - assert(type(version) == "string", "depends.satisfies_constraint: Argument 'version' is not a string.") - assert(type(constraint) == "string", "depends.satisfies_constraint: Argument 'constraint' is not a string.") - return const.constraint_satisfied(version, constraint) -end - --- For package versions, return whether: 'version_a' > 'version_b' -function compare_versions(version_a, version_b) - assert(type(version_a) == "string", "depends.compare_versions: Argument 'version_a' is not a string.") - assert(type(version_b) == "string", "depends.compare_versions: Argument 'version_b' is not a string.") - return const.compareVersions(version_a, version_b) -end - --- Returns 'dep_manifest' updated with information about the 'pkg'. --- 'installed' is table with installed packages --- 'to_install' is table with packages that are selected for installation --- Packages satisfying the dependencies will be searched for in these two tables. -function update_dependency_manifest(pkg, installed, to_install, dep_manifest) - dep_manifest = dep_manifest or {} - assert(type(pkg) == "table", "depends.update_dependency_manifest: Argument 'pkg' is not a table.") - assert(type(installed) == "table", "depends.update_dependency_manifest: Argument 'installed' is not a table.") - assert(type(to_install) == "table", "depends.update_dependency_manifest: Argument 'to_install' is not a table.") - assert(type(dep_manifest) == "table", "depends.update_dependency_manifest: Argument 'dep_manifest' is not a table.") - - local name_ver = pkg.name .. "-" .. (pkg.was_scm_version and "scm" or pkg.version) - - -- add to manifest - if not dep_manifest[name_ver] then - dep_manifest[name_ver] = {} - dep_manifest[name_ver].name = pkg.name - dep_manifest[name_ver].version = pkg.version - dep_manifest[name_ver].was_scm_version = pkg.was_scm_version - dep_manifest[name_ver].arch = pkg.arch - dep_manifest[name_ver].type = pkg.type - dep_manifest[name_ver].path = pkg.path - dep_manifest[name_ver].depends = pkg.depends - dep_manifest[name_ver].conflicts = pkg.conflicts - dep_manifest[name_ver].provides = pkg.provides - dep_manifest[name_ver].license = pkg.license - dep_manifest[name_ver].desc = pkg.desc - dep_manifest[name_ver].url = pkg.url - dep_manifest[name_ver].author = pkg.author - dep_manifest[name_ver].maintainer = pkg.maintainer - - -- add information which dependency is satisfied by which package - if pkg.depends then - - -- TODO: Won't it be better to add OS-specific 'satisfied_by' metadata in a format like OS-specific 'depends' ? - local all_deps = extract_os_specific_depends(pkg.depends) - - dep_manifest[name_ver].satisfied_by = {} - for _, depend in pairs(all_deps) do - - -- find package satisfying the dependency - local satisfying = find_packages(depend, installed)[1] or find_packages(depend, to_install)[1] - satisfying = satisfying.name .. "-" .. satisfying.version - dep_manifest[name_ver].satisfied_by[depend] = satisfying - - -- check whether the satisfying package isn't provided by other one - local provided_by = utils.filter(installed, function(pkg) - return pkg.provides and utils.contains(pkg.provides, satisfying) - end) - if #provided_by == 0 then - provided_by = utils.filter(to_install, function(pkg) - return pkg.provides and utils.contains(pkg.provides, satisfying) - end) - end - - if #provided_by ~= 0 then - if not dep_manifest[name_ver].satisfying_provided_by then - dep_manifest[name_ver].satisfying_provided_by = {} - end - dep_manifest[name_ver].satisfying_provided_by[satisfying] = provided_by[1].name .. "-" .. provided_by[1].version - end - end - - end - end - - return dep_manifest -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/git.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/git.lua deleted file mode 100644 index 808f74d..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/git.lua +++ /dev/null @@ -1,306 +0,0 @@ --- Encapsulated Git functionality - -module ("dist.git", package.seeall) - -require "git" -local sys = require "dist.sys" -local cfg = require "dist.config" - - --- Clone the repository from url to dest_dir -function clone(repository_url, dest_dir, depth, branch) - assert(type(repository_url) == "string", "git.clone: Argument 'repository_url' is not a string.") - assert(type(dest_dir) == "string", "git.clone: Argument 'dest_dir' is not a string.") - dest_dir = sys.abs_path(dest_dir) - - local command = "git clone " .. repository_url - - if depth then - assert(type(depth) == "number", "git.clone: Argument 'depth' is not a number.") - command = command .. " --depth " .. depth - end - - if branch then - assert(type(branch) == "string", "git.clone: Argument 'branch' is not a string.") - command = command .. " -b " .. branch - end - - command = command .. " " .. sys.quote(dest_dir) - if sys.exists(dest_dir) then sys.delete(dest_dir) end - sys.make_dir(dest_dir) - - -- change the current working directory to dest_dir - local prev_current_dir = sys.current_dir() - sys.change_dir(dest_dir) - - -- execute git clone - if not cfg.debug then command = command .. " -q " end - local ok, err = sys.exec(command) - - -- change the current working directory back - sys.change_dir(prev_current_dir) - - return ok, err -end - --- Return table of all refs of the remote repository at the 'git_url'. Ref_type can be "tags" or "heads". -local function get_remote_refs(git_url, ref_type) - assert(type(git_url) == "string", "git.get_remote_refs: Argument 'git_url' is not a string.") - assert(type(ref_type) == "string", "git.get_remote_refs: Argument 'ref_type' is not a string.") - assert(ref_type == "tags" or ref_type == "heads", "git.get_remote_refs: Argument 'ref_type' is not \"tags\" or \"heads\".") - - local refs = {} - - local ok, refs_or_err = pcall(git.protocol.remotes, git_url) - if not ok then return nil, "Error getting refs of the remote repository '" .. git_url .. "': " .. refs_or_err end - - for ref, sha in pairs(refs_or_err) do - if ref:match("%S+/" .. ref_type .. "/%S+") and not ref:match("%^{}") then - table.insert(refs, ref:match("%S+/" .. ref_type .. "/(%S+)")) - end - end - - return refs -end - --- Return table of all tags of the repository at the 'git_url' -function get_remote_tags(git_url) - return get_remote_refs(git_url, "tags") -end - --- Return table of all branches of the repository at the 'git_url' -function get_remote_branches(git_url) - return get_remote_refs(git_url, "heads") -end - --- Checkout specified ref in specified git_repo_dir -function checkout_ref(ref, git_repo_dir, orphaned) - git_repo_dir = git_repo_dir or sys.current_dir() - orphaned = orphaned or false - assert(type(ref) == "string", "git.checkout_ref: Argument 'ref' is not a string.") - assert(type(git_repo_dir) == "string", "git.checkout_ref: Argument 'git_repo_dir' is not a string.") - assert(type(orphaned) == "boolean", "git.checkout_ref: Argument 'orphaned' is not a boolean.") - git_repo_dir = sys.abs_path(git_repo_dir) - - local command = "git checkout " - if orphaned then command = command .. " --orphan " end - command = command .. " " .. ref .. " -f" - if not cfg.debug then command = command .. " -q " end - - local ok, err - if git_repo_dir ~= sys.current_dir() then - local prev_current_dir = sys.current_dir() - sys.change_dir(git_repo_dir) - ok, err = sys.exec(command) - sys.change_dir(prev_current_dir) - else - ok, err = sys.exec(command) - end - - return ok, err -end - --- Checkout specified sha in specified git_repo_dir -function checkout_sha(sha, git_repo_dir) - git_repo_dir = git_repo_dir or sys.current_dir() - assert(type(sha) == "string", "git.checkout_sha: Argument 'sha' is not a string.") - assert(type(git_repo_dir) == "string", "git.checkout_sha: Argument 'git_repo_dir' is not a string.") - git_repo_dir = sys.abs_path(git_repo_dir) - - local dir_changed, prev_current_dir - - if git_repo_dir ~= sys.current_dir() then - prev_current_dir = sys.current_dir() - sys.change_dir(git_repo_dir) - dir_changed = true - end - - local ok, repo_or_err = pcall(git.repo.open, git_repo_dir) - if not ok then return nil, "Error when opening the git repository '" .. git_repo_dir .. "': " .. repo_or_err end - - local err - ok, err = pcall(repo_or_err.checkout, repo_or_err, sha, git_repo_dir) - if not ok then return nil, "Error when checking out the sha '" .. sha .. "' in the git repository '" .. git_repo_dir .. "': " .. err end - - repo_or_err:close() - if dir_changed then sys.change_dir(prev_current_dir) end - - return true -end - --- Create an empty git repository in given directory. -function init(dir) - dir = dir or sys.current_dir() - assert(type(dir) == "string", "git.init: Argument 'dir' is not a string.") - dir = sys.abs_path(dir) - - -- create the 'dir' first, since it causes 'git init' to fail on Windows - -- when the parent directory of 'dir' doesn't exist - local ok, err = sys.make_dir(dir) - if not ok then return nil, err end - - local command = "git init " .. sys.quote(dir) - if not cfg.debug then command = command .. " -q " end - return sys.exec(command) -end - --- Add all files in the 'repo_dir' to the git index. The 'repo_dir' must be --- in the initialized git repository. -function add_all(repo_dir) - repo_dir = repo_dir or sys.current_dir() - assert(type(repo_dir) == "string", "git.add_all: Argument 'repo_dir' is not a string.") - repo_dir = sys.abs_path(repo_dir) - - local ok, prev_dir, msg - ok, prev_dir = sys.change_dir(repo_dir); - if not ok then return nil, err end - - ok, msg = sys.exec("git add -A -f " .. sys.quote(repo_dir)) - sys.change_dir(prev_dir) - - return ok, msg -end - --- Commit all indexed files in 'repo_dir' with the given commit 'message'. --- The 'repo_dir' must be in the initialized git repository. -function commit(message, repo_dir) - repo_dir = repo_dir or sys.current_dir() - message = message or "commit by luadist-git" - assert(type(message) == "string", "git.commit: Argument 'message' is not a string.") - assert(type(repo_dir) == "string", "git.commit: Argument 'repo_dir' is not a string.") - repo_dir = sys.abs_path(repo_dir) - - local ok, prev_dir, msg - ok, prev_dir = sys.change_dir(repo_dir); - if not ok then return nil, err end - - local command = "git commit -m " .. sys.quote(message) - if not cfg.debug then command = command .. " -q " end - ok, msg = sys.exec(command) - sys.change_dir(prev_dir) - - return ok, msg -end - - --- Rename branch 'old_name' to 'new_name'. -- The 'repo_dir' must be --- in the initialized git repository and the branch 'new_name' must --- not already exist in that repository. -function rename_branch(old_name, new_name, repo_dir) - repo_dir = repo_dir or sys.current_dir() - assert(type(old_name) == "string", "git.rename_branch: Argument 'old_name' is not a string.") - assert(type(new_name) == "string", "git.rename_branch: Argument 'new_name' is not a string.") - assert(type(repo_dir) == "string", "git.rename_branch: Argument 'repo_dir' is not a string.") - repo_dir = sys.abs_path(repo_dir) - - local ok, prev_dir, msg - ok, prev_dir = sys.change_dir(repo_dir); - if not ok then return nil, err end - - ok, msg = sys.exec("git branch -m " .. old_name .. " " .. new_name) - sys.change_dir(prev_dir) - - return ok, msg -end - --- Push the ref 'ref_name' from the 'repo_dir' to the remote git --- repository 'git_repo_url'. If 'all_tags' is set to true, all tags --- will be pushed, in addition to the explicitly given ref. --- If 'delete' is set to 'true' then the explicitly given remote ref --- will be deleted, not pushed. -function push_ref(repo_dir, ref_name, git_repo_url, all_tags, delete) - repo_dir = repo_dir or sys.current_dir() - all_tags = all_tags or false - delete = delete or false - assert(type(repo_dir) == "string", "git.push_ref: Argument 'repo_dir' is not a string.") - assert(type(git_repo_url) == "string", "git.push_ref: Argument 'git_repo_url' is not a string.") - assert(type(ref_name) == "string", "git.push_ref: Argument 'ref_name' is not a string.") - assert(type(all_tags) == "boolean", "git.push_ref: Argument 'all_tags' is not a boolean.") - assert(type(delete) == "boolean", "git.push_ref: Argument 'delete' is not a boolean.") - repo_dir = sys.abs_path(repo_dir) - - local ok, prev_dir, msg - ok, prev_dir = sys.change_dir(repo_dir); - if not ok then return nil, err end - - local command = "git push " .. git_repo_url - if all_tags then command = command .. " --tags " end - if delete then command = command .. " --delete " end - command = command .. " " .. ref_name .. " -f " - if not cfg.debug then command = command .. " -q " end - - ok, msg = sys.exec(command) - sys.change_dir(prev_dir) - - return ok, msg -end - --- Creates the tag 'tag_name' in given 'repo_dir', which must be --- in the initialized git repository -function create_tag(repo_dir, tag_name) - repo_dir = repo_dir or sys.current_dir() - assert(type(repo_dir) == "string", "git.create_tag: Argument 'repo_dir' is not a string.") - assert(type(tag_name) == "string", "git.create_tag: Argument 'tag_name' is not a string.") - repo_dir = sys.abs_path(repo_dir) - - local ok, prev_dir, msg - ok, prev_dir = sys.change_dir(repo_dir); - if not ok then return nil, err end - - ok, msg = sys.exec("git tag " .. tag_name .. " -f ") - sys.change_dir(prev_dir) - - return ok, msg -end - --- Fetch given 'ref_name' from the remote 'git_repo_url' to the local repository --- 'repo_dir' and return its sha. 'ref_type' can be "tag" or "head". -local function fetch_ref(repo_dir, git_repo_url, ref_name, ref_type) - repo_dir = repo_dir or sys.current_dir() - assert(type(repo_dir) == "string", "git.fetch_ref: Argument 'repo_dir' is not a string.") - assert(type(git_repo_url) == "string", "git.fetch_ref: Argument 'git_repo_url' is not a string.") - assert(type(ref_name) == "string", "git.fetch_ref: Argument 'ref_name' is not a string.") - assert(type(ref_type) == "string", "git.fetch_ref: Argument 'ref_type' is not a string.") - assert(ref_type == "tag" or ref_type == "head", "git.get_remote_refs: Argument 'ref_type' is not \"tag\" or \"head\".") - repo_dir = sys.abs_path(repo_dir) - - local refstring = "refs/" .. ref_type .. "s/" .. ref_name - - local suppress_fetch_progress = not cfg.debug - local ok, repo_or_err = pcall(git.repo.open, repo_dir) - if not ok then return nil, "Error when opening the git repository '" .. repo_dir .. "': " .. repo_or_err end - - local ok, pack_or_err, sha = pcall(git.protocol.fetch, git_repo_url, repo_or_err, refstring, suppress_fetch_progress) - if not ok then return nil, "Error when fetching ref '" .. refstring .. "' from git repository '" .. git_repo_url .. "': " .. pack_or_err end - - repo_or_err:close() - pack_or_err:close() - - return sha -end - --- Fetch given 'tag_name' from the remote 'git_repo_url' to the local repository --- 'repo_dir' and save it as a tag with the same 'tag_name'. -function fetch_tag(repo_dir, git_repo_url, tag_name) - return fetch_ref(repo_dir, git_repo_url, tag_name, "tag") -end - --- Fetch given 'branch_name' from the remote 'git_repo_url' to the local repository --- 'repo_dir' and save it as a branch with the same 'branch_name'. -function fetch_branch(repo_dir, git_repo_url, branch_name) - return fetch_ref(repo_dir, git_repo_url, branch_name, "head") -end - --- Create the git repository and return the repo object (which can be used in checkout_sha etc.) --- If the 'dir' exists, it's deleted prior to creating the git repository. -function create_repo(dir) - assert(type(dir) == "string", "git.create_repo: Argument 'dir' is not a string.") - - if sys.exists(dir) then sys.delete(dir) end - - local ok, repo_or_err = pcall(git.repo.create, dir) - if not ok then return nil, "Error when creating the git repository '" .. dir .. "': " .. repo_or_err end - - repo_or_err:close() - return true -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/init.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/init.lua deleted file mode 100644 index 50c4b7e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/init.lua +++ /dev/null @@ -1,349 +0,0 @@ --- main API of LuaDist - -module ("dist", package.seeall) - -local cfg = require "dist.config" -local depends = require "dist.depends" -local git = require "dist.git" -local sys = require "dist.sys" -local package = require "dist.package" -local mf = require "dist.manifest" -local utils = require "dist.utils" - --- Return the deployment directory. -function get_deploy_dir() - return sys.abs_path(cfg.root_dir) -end - --- Return packages deployed in 'deploy_dir' also with their provides. -function get_deployed(deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(deploy_dir) == "string", "dist.get_deployed: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local deployed = depends.get_installed(deploy_dir) - local provided = {} - - for _, pkg in pairs(deployed) do - for _, provided_pkg in pairs(depends.get_provides(pkg)) do - provided_pkg.provided_by = pkg.name .. "-" .. pkg.version - table.insert(provided, provided_pkg) - end - end - - for _, provided_pkg in pairs(provided) do - table.insert(deployed, provided_pkg) - end - - deployed = depends.sort_by_names(deployed) - return deployed -end - --- Download new 'manifest_file' from repository and returns it. --- Return nil and error message on error. -function update_manifest(deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(deploy_dir) == "string", "dist.update_manifest: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - -- TODO: use 'deploy_dir' argument in manifest functions - - -- retrieve the new manifest (forcing no cache use) - local manifest, err = mf.get_manifest(nil, true) - - if manifest then - return manifest - else - return nil, err - end -end - --- Install 'package_names' to 'deploy_dir', using optional CMake 'variables'. -function install(package_names, deploy_dir, variables) - if not package_names then return true end - deploy_dir = deploy_dir or cfg.root_dir - if type(package_names) == "string" then package_names = {package_names} end - - assert(type(package_names) == "table", "dist.install: Argument 'package_names' is not a table or string.") - assert(type(deploy_dir) == "string", "dist.install: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - -- find installed packages - local installed = depends.get_installed(deploy_dir) - - -- get manifest - local manifest, err = mf.get_manifest() - if not manifest then return nil, "Error getting manifest: " .. err end - - -- get dependency manifest - -- TODO: Is it good that dep_manifest is deploy_dir-specific? - -- Probably it'd be better not to be specific, but then there're - -- problems with 'provides'. E.g. What to do if there's a module - -- installed, that is provided by two different modules in two deploy_dirs? - local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file)) - local dep_manifest, status = {} - if sys.exists(dep_manifest_file) and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then - status, dep_manifest = mf.load_manifest(dep_manifest_file) - if not dep_manifest then return nil, status end - end - - -- resolve dependencies - local dependencies, dep_manifest_or_err = depends.get_depends(package_names, installed, manifest, dep_manifest, deploy_dir, false, false) - if not dependencies then return nil, dep_manifest_or_err end - if #dependencies == 0 then return nil, "No packages to install." end - - -- save updated dependency manifest - local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file)) - if not ok then return nil, err end - ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file) - if not ok then return nil, err end - - -- fetch the packages from repository - local fetched_pkgs = {} - for _, pkg in pairs(dependencies) do - local fetched_pkg, err = package.fetch_pkg(pkg, sys.make_path(deploy_dir, cfg.temp_dir)) - if not fetched_pkg then return nil, err end - table.insert(fetched_pkgs, fetched_pkg) - end - - -- install fetched packages - for _, pkg in pairs(fetched_pkgs) do - local ok, err = package.install_pkg(pkg.download_dir, deploy_dir, variables, pkg.preserve_pkg_dir) - if not ok then return nil, err end - end - - return true -end - --- Manually deploy packages from 'package_dirs' to 'deploy_dir', using optional --- CMake 'variables'. The 'package_dirs' are preserved (will not be deleted). -function make(deploy_dir, package_dirs, variables) - deploy_dir = deploy_dir or cfg.root_dir - package_dirs = package_dirs or {} - - assert(type(deploy_dir) == "string", "dist.make: Argument 'deploy_dir' is not a string.") - assert(type(package_dirs) == "table", "dist.make: Argument 'package_dirs' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - for _, dir in pairs(package_dirs) do - local ok, err = package.install_pkg(sys.abs_path(dir), deploy_dir, variables, true) - if not ok then return nil, err end - end - return true -end - --- Remove 'package_names' from 'deploy_dir' and return the number of removed --- packages. -function remove(package_names, deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - if type(package_names) == "string" then package_names = {package_names} end - - assert(type(package_names) == "table", "dist.remove: Argument 'package_names' is not a string or table.") - assert(type(deploy_dir) == "string", "dist.remove: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local pkgs_to_remove = {} - local installed = depends.get_installed(deploy_dir) - - -- find packages to remove - if #package_names == 0 then - pkgs_to_remove = installed - else - pkgs_to_remove = depends.find_packages(package_names, installed) - end - - -- remove them - for _, pkg in pairs(pkgs_to_remove) do - local pkg_distinfo_dir = sys.make_path(cfg.distinfos_dir, pkg.name .. "-" .. pkg.version) - local ok, err = package.remove_pkg(pkg_distinfo_dir, deploy_dir) - if not ok then return nil, err end - end - - return #pkgs_to_remove -end - --- Download 'pkg_names' to 'fetch_dir' and return the table of their directories. -function fetch(pkg_names, fetch_dir) - fetch_dir = fetch_dir or sys.current_dir() - assert(type(pkg_names) == "table", "dist.fetch: Argument 'pkg_names' is not a string or table.") - assert(type(fetch_dir) == "string", "dist.fetch: Argument 'fetch_dir' is not a string.") - fetch_dir = sys.abs_path(fetch_dir) - - local manifest = mf.get_manifest() - - local pkgs_to_fetch = {} - for _, pkg_name in pairs(pkg_names) do - - -- retrieve available versions - local versions, err = package.retrieve_versions(pkg_name, manifest) - if not versions then return nil, err end - for _, version in pairs(versions) do - table.insert(manifest, version) - end - - local packages = depends.find_packages(pkg_name, manifest) - if #packages == 0 then return nil, "No packages found for '" .. pkg_name .. "'." end - - packages = depends.sort_by_versions(packages) - table.insert(pkgs_to_fetch, packages[1]) - end - - local fetched_dirs = {} - for _, pkg in pairs(pkgs_to_fetch) do - local fetched_pkg, err = package.fetch_pkg(pkg, fetch_dir) - if not fetched_pkg then return nil, err end - table.insert(fetched_dirs, fetched_pkg.download_dir) - end - - return fetched_dirs -end - --- Upload binary version of given modules installed in the specified --- 'deploy_dir' to the repository specified by provided base url. --- Return the number of uploaded packages. --- --- Organization of uploaded modules and their repositories is subject --- to the following conventions: --- - destination repository is: 'DEST_GIT_BASE_URL/MODULE_NAME' --- - module will be uploaded to the branch: 'ARCH-TYPE' according --- to the arch and type of the user's machine --- - the module will be tagged as: 'VERSION-ARCH-TYPE' (if the tag already --- exists, it will be overwritten) --- --- E.g. assume that the module 'lua-5.1.4' is installed on the 32bit Linux --- system (Linux-i686). When this function is called with the module name --- 'lua' and base url 'git@github.com:LuaDist', then the binary version --- of the module 'lua', that is installed on the machine, will be uploaded --- to the branch 'Linux-i686' of the repository 'git@github.com:LuaDist/lua.git' --- and tagged as '5.1.4-Linux-i686'. -function upload_modules(deploy_dir, module_names, dest_git_base_url) - deploy_dir = deploy_dir or cfg.root_dir - if type(module_names) == "string" then module_names = {module_names} end - assert(type(deploy_dir) == "string", "dist.upload_module: Argument 'deploy_dir' is not a string.") - assert(type(module_names) == "table", "dist.upload_module: Argument 'module_name' is not a string or table.") - assert(type(dest_git_base_url) == "string", "dist.upload_module: Argument 'dest_git_base_url' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local modules_to_upload = {} - local installed = depends.get_installed(deploy_dir) - - -- find modules to upload - if #module_names == 0 then - modules_to_upload = installed - else - modules_to_upload = depends.find_packages(module_names, installed) - end - - for _, installed_module in pairs(modules_to_upload) do - - -- set names - local branch_name = cfg.arch .. "-" .. cfg.type - local tag_name = installed_module.version .. "-" .. branch_name - local full_name = installed_module.name .. "-" .. tag_name - local tmp_dir = sys.make_path(deploy_dir, cfg.temp_dir, full_name .. "-to-upload") - local dest_git_url = dest_git_base_url .. "/" .. installed_module.name .. ".git" - local distinfo_file = sys.make_path(deploy_dir, cfg.distinfos_dir, installed_module.name .. "-" .. installed_module.version, "dist.info") - - -- create temporary directory (delete previous if already exists) - if sys.exists(tmp_dir) then sys.delete(tmp_dir) end - local ok, err = sys.make_dir(tmp_dir) - if not ok then return nil, err end - - -- copy the module files for all enabled components - for _, component in ipairs(cfg.components) do - if installed_module.files[component] then - for _, file in ipairs(installed_module.files[component]) do - local file_path = sys.make_path(deploy_dir, file) - local dest_dir = sys.parent_dir(sys.make_path(tmp_dir, file)) - if sys.is_file(file_path) then - sys.make_dir(dest_dir) - sys.copy(file_path, dest_dir) - end - end - end - end - - -- add module's dist.info file - sys.copy(distinfo_file, tmp_dir) - - -- create git repo - ok, err = git.init(tmp_dir) - if not ok then return nil, "Error initializing empty git repository in '" .. tmp_dir .. "': " .. err end - - -- add all files - ok, err = git.add_all(tmp_dir) - if not ok then return nil, "Error adding all files to the git index in '" .. tmp_dir .. "': " .. err end - - -- create commit - ok, err = git.commit("[luadist-git] add " .. full_name .. " [ci skip]", tmp_dir) - if not ok then return nil, "Error commiting changes in '" .. tmp_dir .. "': " .. err end - - -- rename branch - ok, err = git.rename_branch("master", branch_name, tmp_dir) - if not ok then return nil, "Error renaming branch 'master' to '" .. branch_name .. "' in '" .. tmp_dir .. "': " .. err end - - -- create tag - ok, err = git.create_tag(tmp_dir, tag_name) - if not ok then return nil, "Error creating tag '" .. tag_name .. "' in '" .. tmp_dir .. "': " .. err end - - print("Uploading " .. full_name .. " to " .. dest_git_url .. "...") - - -- push to the repository - ok, err = git.push_ref(tmp_dir, branch_name, dest_git_url, true) - if not ok then return nil, "Error when pushing branch '" .. branch_name .. "' and tag '" .. tag_name .. "' to '" .. dest_git_url .. "': " .. err end - - -- delete temporary directory (if not in debug mode) - if not cfg.debug then sys.delete(tmp_dir) end - end - - return #modules_to_upload -end - --- Returns table with information about module's dependencies, using the cache. -function dependency_info(module, deploy_dir) - cache_file = cache_file or sys.abs_path(sys.make_path(cfg.root_dir, cfg.dep_cache_file)) - assert(type(module) == "string", "dist.dependency_info: Argument 'module' is not a string.") - assert(type(deploy_dir) == "string", "dist.dependency_info: Argument 'deploy_dir' is not a string.") - - -- get manifest - local manifest, err = mf.get_manifest() - if not manifest then return nil, "Error getting manifest: " .. err end - - -- get dependency manifest - -- TODO: Is it good that dep_manifest is deploy_dir-specific? - -- Probably it'd be better not to be specific, but then there're - -- problems with 'provides'. E.g. What to do if there's a module - -- installed, that is provided by two different modules in two deploy_dirs? - local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file)) - local dep_manifest, status = {} - if sys.exists(dep_manifest_file) and cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then - status, dep_manifest = mf.load_manifest(dep_manifest_file) - if not dep_manifest then return nil, status end - end - - -- force getting the dependency information - local installed = {} - - -- resolve dependencies - local dependencies, dep_manifest_or_err = depends.get_depends(module, installed, manifest, dep_manifest, deploy_dir, false, true and not cfg.debug) - if not dependencies then return nil, dep_manifest_or_err end - - -- save updated dependency manifest - local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file)) - if not ok then return nil, err end - ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file) - if not ok then return nil, err end - - -- collect just relevant dependencies from dependency manifest - local relevant_deps = {} - for _, dep in pairs(dependencies) do - local name_ver = dep.name .. "-" .. (dep.was_scm_version and "scm" or dep.version) - if dep_manifest_or_err[name_ver] then - table.insert(relevant_deps, dep_manifest_or_err[name_ver]) - else - return nil, "Error: dependency information for '" .. name_ver .. "' not found in dependency manifest." - end - end - - return relevant_deps -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/logger.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/logger.lua deleted file mode 100644 index 7843223..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/logger.lua +++ /dev/null @@ -1,64 +0,0 @@ --- Simple logger for LuaDist. - -module ("dist.logger", package.seeall) - -local cfg = require "dist.config" -local sys = require "dist.sys" - --- Open 'log_file' and return a log, or nil and error msg on error. -local function get_log(log_file) - log_file = log_file or cfg.log_file - assert(type(log_file) == "string", "log.get_log: Argument 'log_file' is not a string.") - log_file = sys.abs_path(log_file) - - sys.make_dir(sys.parent_dir(log_file)) - local log, err = io.open(log_file, "a") - if not log then - return nil, "Error: can't open a logfile '" .. log_file .. "': " .. err - else - return log - end -end - --- Set the default log. -local log_file = get_log(cfg.log_file) - --- Log levels used. -local log_levels = { - DEBUG = 0, -- Fine-grained informational events that are most useful to debug an application. - INFO = 1, -- Informational messages that highlight the progress of the application at coarse-grained level. - WARN = 2, -- Potentially harmful situations. - ERROR = 3, -- Error events that might still allow the application to continue running. - FATAL = 4, -- Very severe error events that would presumably lead the application to abort. -} - --- Write 'message' with 'level' to 'log'. -local function write(level, ...) - assert(type(level) == "string", "log.write: Argument 'level' is not a string.") - assert(#arg > 0, "log.write: No message arguments provided.") - assert(type(log_levels[level]) == "number", "log.write: Unknown log level used: '" .. level .. "'.") - - level = level:upper() - local message = table.concat(arg, " ") - - -- Check if writing for this log level is enabled. - if cfg.write_log_level and log_levels[level] >= log_levels[cfg.write_log_level] then - log_file:write(os.date("%Y-%m-%d %H:%M:%S") .. " [" .. level .. "]\t" .. message .. "\n") - log_file:flush() - end - - -- Check if printing for this log level is enabled. - if cfg.print_log_level and log_levels[level] >= log_levels[cfg.print_log_level] then - print(message) - end -end - --- Functions with defined log levels for simple use. -function debug(...) return write("DEBUG", ...) end -function info(...) return write("INFO", ...) end -function warn(...) return write("WARN", ...) end -function error(...) return write("ERROR", ...) end -function fatal(...) return write("FATAL", ...) end - --- Function with explicitly specified log level. -function log(level, ...) return write(level, ...) end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/manifest.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/manifest.lua deleted file mode 100644 index ccaad13..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/manifest.lua +++ /dev/null @@ -1,248 +0,0 @@ --- Working with manifest and dist.info files - -module ("dist.manifest", package.seeall) - -local cfg = require "dist.config" -local git = require "dist.git" -local sys = require "dist.sys" -local utils = require "dist.utils" - --- Return the manifest table from 'manifest_file'. If the manifest is in cache, --- then the cached version is used. You can set the cache timeout value in --- 'config.cache_timeout' variable. --- If optional 'force_no_cache' parameter is true, then the cache is not used. -function get_manifest(manifest_file, force_no_cache) - manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file) - force_no_cache = force_no_cache or false - - assert(type(manifest_file) == "string", "manifest.get_manifest: Argument 'manifest_file' is not a string.") - assert(type(force_no_cache) == "boolean", "manifest.get_manifest: Argument 'force_no_cache' is not a boolean.") - manifest_file = sys.abs_path(manifest_file) - - -- download new manifest to the cache if not present or cache not used or cache expired - if not sys.exists(manifest_file) or force_no_cache or not cfg.cache or utils.cache_timeout_expired(cfg.cache_timeout, manifest_file) then - local manifest_dest = sys.parent_dir(manifest_file) or sys.current_dir() - local ok, err = download_manifest(manifest_dest, cfg.repos) - if not ok then return nil, "Error when downloading manifest: " .. err end - end - - -- load manifest from cache - local status, ret = load_manifest(manifest_file) - if not status then return nil, "Error when loading manifest: " .. ret end - - return ret -end - --- Download manifest from the table of git 'repository_urls' to 'dest_dir' and return true on success --- and nil and error message on error. -function download_manifest(dest_dir, repository_urls) - dest_dir = dest_dir or sys.make_path(cfg.root_dir, cfg.cache_dir) - repository_urls = repository_urls or cfg.repos - if type(repository_urls) == "string" then repository_urls = {repository_urls} end - - assert(type(dest_dir) == "string", "manifest.download_manifest: Argument 'dest_dir' is not a string.") - assert(type(repository_urls) == "table", "manifest.download_manifest: Argument 'repository_urls' is not a table or string.") - dest_dir = sys.abs_path(dest_dir) - - -- define used files and directories - local manifest_filename = sys.extract_name(cfg.manifest_file) - local manifest_file = sys.make_path(dest_dir, manifest_filename) - local temp_dir = sys.make_path(cfg.root_dir, cfg.temp_dir) - - -- ensure that destination directory exists - local ok, err = sys.make_dir(dest_dir) - if not ok then return nil, err end - - -- retrieve manifests from repositories and collect them into one manifest table - local manifest = {} - - if #repository_urls == 0 then return nil, "No repository url specified." end - - print("Downloading repository information...") - for k, repo in pairs(repository_urls) do - local clone_dir = sys.make_path(temp_dir, "repository_" .. tostring(k)) - - -- clone the repo and add its '.gitmodules' file to the manifest table - - ok, err = git.create_repo(clone_dir) - - local sha - if ok then sha, err = git.fetch_branch(clone_dir, repo, "master") end - if sha then ok, err = git.checkout_sha(sha, clone_dir) end - - if not (ok and sha) then - if not cfg.debug then sys.delete(clone_dir) end - return nil, "Error when downloading the manifest from repository with url: '" .. repo .. "': " .. err - else - for _, pkg in pairs(load_gitmodules(sys.make_path(clone_dir, ".gitmodules"))) do - table.insert(manifest, pkg) - end - end - if not cfg.debug then sys.delete(clone_dir) end - end - - -- save the new manifest table to the file - ok, err = save_manifest(manifest, manifest_file) - if not ok then return nil, err end - - return true -end - --- A secure loadfile function --- If file code chunk has upvalues, the first upvalue is set to the given --- environement, if that parameter is given, or to the value of the global environment. -local function secure_loadfile(file, env) - assert(type(file) == "string", "secure_loadfile: Argument 'file' is not a string.") - - -- use the given (or create a new) restricted environment - local env = env or {} - - -- load the file and run in a protected call with the restricted env - -- setfenv is deprecated in lua 5.2 in favor of giving env in arguments - -- the additional loadfile arguments are simply ignored for previous lua versions - local f, err = loadfile(file, 'bt', env) - if f then - if setfenv ~= nil then - setfenv(f, env) - end - return pcall(f) - else - return nil, err - end -end - --- Load and return manifest table from the manifest file. --- If manifest file not present, return nil. -function load_manifest(manifest_file) - manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file) - - return secure_loadfile(sys.abs_path(manifest_file)) -end - --- Load '.gitmodules' file and returns manifest table. --- If the file is not present, return nil. -function load_gitmodules(gitmodules_file) - gitmodules_file = gitmodules_file or sys.make_path(cfg.root_dir, cfg.manifest_file) - assert(type(gitmodules_file) == "string", "manifest.load_gitmodules: Argument 'gitmodules_file' is not a string.") - gitmodules_file = sys.abs_path(gitmodules_file) - - if sys.exists(gitmodules_file) then - -- load the .gitmodules file - local file, err = io.open(gitmodules_file, "r") - if not file then return nil, "Error when opening the .gitmodules file '" .. gitmodules_file .. "':" .. err end - - local mf_text = file:read("*a") - file:close() - if not mf_text then return nil, "Error when reading the .gitmodules file '" .. gitmodules_file .. "':" .. err end - - manifest = {} - for url in mf_text:gmatch("git://%S+/%S+") do - pkg = {name = url:match("git://%S+/(%S+)%.git") or url:match("git://%S+/(%S+)"), version = "scm", path = url} - table.insert(manifest, pkg) - end - - return manifest - else - return nil, "Error when loading the .gitmodules: file '" .. gitmodules_file .. "' doesn't exist." - end -end - --- Save manifest table to the 'file' -function save_manifest(manifest_table, file) - assert(type(manifest_table) == "table", "manifest.save_distinfo: Argument 'manifest_table' is not a table.") - assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.") - file = sys.abs_path(file) - - -- Print table 'tbl' to io stream 'file'. - local function print_table(file, tbl, in_nested_table) - for k, v in pairs(tbl) do - -- print key - if in_nested_table then file:write("\t\t") end - if type(k) ~= "number" then - file:write("['" .. k .. "']" .. " = ") - end - -- print value - if type(v) == "table" then - file:write("{\n") - print_table(file, v, true) - if in_nested_table then file:write("\t") end - file:write("\t}") - else - if in_nested_table then file:write("\t") end - if type(v) == "string" then - file:write('[[' .. v .. ']]') - else - file:write(tostring(v)) - end - end - file:write(",\n") - end - end - - local manifest_file = io.open(file, "w") - if not manifest_file then return nil, "Error when saving manifest: cannot open the file '" .. file .. "'." end - - manifest_file:write('return {\n') - print_table(manifest_file, manifest_table) - manifest_file:write('},\ntrue') - manifest_file:close() - - return true -end - --- Load and return package info table from the distinfo_file file. --- If file not present, return nil. -function load_distinfo(distinfo_file) - assert(type(distinfo_file) == "string", "manifest.load_distinfo: Argument 'distinfo_file' is not a string.") - distinfo_file = sys.abs_path(distinfo_file) - - -- load the distinfo file - local distinfo_env = {} - local status, ret = secure_loadfile(distinfo_file, distinfo_env) - if not status then return nil, "Error when loading package info: " .. ret end - - return distinfo_env -end - --- Save distinfo table to the 'file' -function save_distinfo(distinfo_table, file) - assert(type(distinfo_table) == "table", "manifest.save_distinfo: Argument 'distinfo_table' is not a table.") - assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.") - file = sys.abs_path(file) - - -- Print table 'tbl' to io stream 'file'. - local function print_table(file, tbl, in_nested_table) - for k, v in pairs(tbl) do - -- print key - if type(k) ~= "number" then - file:write(k .. " = ") - end - -- print value - if type(v) == "table" then - file:write("{\n") - print_table(file, v, true) - file:write("}\n") - elseif type(v) == "string" then - if in_nested_table then - file:write('[[' .. v .. ']]') - else - file:write('"' .. v .. '"') - end - else - file:write(v) - end - if in_nested_table then - file:write(",") - end - file:write("\n") - end - end - - local distinfo_file = io.open(file, "w") - if not distinfo_file then return nil, "Error when saving dist-info table: cannot open the file '" .. file .. "'." end - - print_table(distinfo_file, distinfo_table) - distinfo_file:close() - - return true -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/package.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/package.lua deleted file mode 100644 index da399c1..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/package.lua +++ /dev/null @@ -1,596 +0,0 @@ --- Package functions - -module ("dist.package", package.seeall) - -local cfg = require "dist.config" -local git = require "dist.git" -local sys = require "dist.sys" -local mf = require "dist.manifest" -local utils = require "dist.utils" -local depends = require "dist.depends" - --- Return whether the package in given 'pkg_dir' is of a source type. -function is_source_type(pkg_dir) - assert(type(pkg_dir) == "string", "package.is_source_type: Argument 'pkg_dir' is not a string.") - pkg_dir = sys.abs_path(pkg_dir) - return utils.to_boolean(sys.exists(sys.make_path(pkg_dir, "CMakeLists.txt"))) -end - --- Ensure proper arch and type for the given source 'dist_info' table and return it. --- WARNING: this function should be used only for 'dist_info' tables of modules that are of a source type! -function ensure_source_arch_and_type(dist_info) - assert(type(dist_info) == "table", "package.ensure_source_arch_and_type: Argument 'dist_info' is not a table.") - dist_info.arch = dist_info.arch or "Universal" - dist_info.type = dist_info.type or "source" - return dist_info -end - --- Remove package from 'pkg_distinfo_dir' of 'deploy_dir'. -function remove_pkg(pkg_distinfo_dir, deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(pkg_distinfo_dir) == "string", "package.remove_pkg: Argument 'pkg_distinfo_dir' is not a string.") - assert(type(deploy_dir) == "string", "package.remove_pkg: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local abs_pkg_distinfo_dir = sys.make_path(deploy_dir, pkg_distinfo_dir) - - -- check for 'dist.info' - local info, err = mf.load_distinfo(sys.make_path(abs_pkg_distinfo_dir, "dist.info")) - if not info then return nil, "Error removing package from '" .. pkg_distinfo_dir .. "' - it doesn't contain valid 'dist.info' file." end - if not info.files then return nil, "File '" .. sys.make_path(pkg_distinfo_dir, "dist.info") .."' doesn't contain list of installed files." end - - -- remove files installed as components of this package - for _, component in ipairs(cfg.components) do - if info.files[component] then - for i = #info.files[component], 1, -1 do - local f = info.files[component][i] - f = sys.make_path(deploy_dir,f) - if sys.is_file(f) then - sys.delete(f) - elseif sys.is_dir(f) then - local dir_files, err = sys.get_file_list(f) - if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end - if #dir_files == 0 then sys.delete(f) end - end - -- delete also all parent directories if empty - local parents = sys.parents_up_to(f, deploy_dir) - for _, parent in ipairs(parents) do - if sys.is_dir(parent) then - local dir_files, err = sys.get_file_list(parent) - if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end - if #dir_files == 0 then - sys.delete(parent) - end - end - end - end - end - end - - -- remove removed components also from 'dist.info' - for _, component in ipairs(cfg.components) do - info.files[component] = nil - end - - -- delete the package information from deploy_dir - local ok = sys.delete(abs_pkg_distinfo_dir) - if not ok then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "'." end - - -- if the package was not completely removed (e.g. some components remain), - -- save the new version of its 'dist.info' - local comp_num = 0 - for _, _ in pairs(info.files) do comp_num = comp_num + 1 end - if comp_num ~= 0 then - sys.make_dir(abs_pkg_distinfo_dir) - local ok, err = mf.save_distinfo(info, sys.make_path(abs_pkg_distinfo_dir, "dist.info")) - if not ok then return nil, "Error resaving the 'dist.info': " .. err end - end - - return ok -end - --- Install package from 'pkg_dir' to 'deploy_dir', using optional CMake 'variables'. --- Optional 'preserve_pkg_dir' argument specified whether to preserve the 'pkg_dir'. -function install_pkg(pkg_dir, deploy_dir, variables, preserve_pkg_dir) - deploy_dir = deploy_dir or cfg.root_dir - variables = variables or {} - preserve_pkg_dir = preserve_pkg_dir or false - - assert(type(pkg_dir) == "string", "package.install_pkg: Argument 'pkg_dir' is not a string.") - assert(type(deploy_dir) == "string", "package.install_pkg: Argument 'deploy_dir' is not a string.") - assert(type(variables) == "table", "package.install_pkg: Argument 'variables' is not a table.") - assert(type(preserve_pkg_dir) == "boolean", "package.install_pkg: Argument 'preserve_pkg_dir' is not a boolean.") - - pkg_dir = sys.abs_path(pkg_dir) - deploy_dir = sys.abs_path(deploy_dir) - - -- check for dist.info - local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info")) - if not info then return nil, "Error installing: the directory '" .. pkg_dir .. "' doesn't exist or doesn't contain valid 'dist.info' file." end - - -- check if the package is source - if is_source_type(pkg_dir) then info = ensure_source_arch_and_type(info) end - - -- check package's architecture - if not (info.arch == "Universal" or info.arch == cfg.arch) then - return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture '" .. info.arch .. "' is not suitable for this machine." - end - - -- check package's type - if not (info.type == "all" or info.type == "source" or info.type == cfg.type) then - return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture type '" .. info.type .. "' is not suitable for this machine." - end - - local ok, err - - -- if package is of binary type, just deploy it - if info.type ~= "source" then - ok, err = deploy_binary_pkg(pkg_dir, deploy_dir) - - -- else build and then deploy - else - - -- check if we have cmake - ok = utils.system_dependency_available("cmake", "cmake --version") - if not ok then return nil, "Error when installing: Command 'cmake' not available on the system." end - - -- set cmake variables - local cmake_variables = {} - - -- set variables from config file - for k, v in pairs(cfg.variables) do - cmake_variables[k] = v - end - - -- set variables specified as argument - for k, v in pairs(variables) do - cmake_variables[k] = v - end - - cmake_variables.CMAKE_INCLUDE_PATH = table.concat({cmake_variables.CMAKE_INCLUDE_PATH or "", sys.make_path(deploy_dir, "include")}, ";") - cmake_variables.CMAKE_LIBRARY_PATH = table.concat({cmake_variables.CMAKE_LIBRARY_PATH or "", sys.make_path(deploy_dir, "lib"), sys.make_path(deploy_dir, "bin")}, ";") - cmake_variables.CMAKE_PROGRAM_PATH = table.concat({cmake_variables.CMAKE_PROGRAM_PATH or "", sys.make_path(deploy_dir, "bin")}, ";") - - -- build the package and deploy it - ok, err = build_pkg(pkg_dir, deploy_dir, cmake_variables) - if not ok then return nil, err end - - end - - -- delete directory of fetched package - if not (cfg.debug or preserve_pkg_dir) then sys.delete(pkg_dir) end - - return ok, err -end - --- Build and deploy package from 'src_dir' to 'deploy_dir' using 'variables'. --- Return directory to which the package was built or nil on error. --- 'variables' is table of optional CMake variables. -function build_pkg(src_dir, deploy_dir, variables) - deploy_dir = deploy_dir or cfg.root_dir - variables = variables or {} - - assert(type(src_dir) == "string", "package.build_pkg: Argument 'src_dir' is not a string.") - assert(type(deploy_dir) == "string", "package.build_pkg: Argument 'deploy_dir' is not a string.") - assert(type(variables) == "table", "package.build_pkg: Argument 'variables' is not a table.") - - src_dir = sys.abs_path(src_dir) - deploy_dir = sys.abs_path(deploy_dir) - - -- check for dist.info - local info, err = mf.load_distinfo(sys.make_path(src_dir, "dist.info")) - if not info then return nil, "Error building package from '" .. src_dir .. "': it doesn't contain valid 'dist.info' file." end - local pkg_name = info.name .. "-" .. info.version - - -- set machine information - info.arch = cfg.arch - info.type = cfg.type - - -- create CMake build dir - local cmake_build_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir, pkg_name .. "-CMake-build")) - sys.make_dir(cmake_build_dir) - - -- create cmake cache - variables["CMAKE_INSTALL_PREFIX"] = deploy_dir - local cache_file = io.open(sys.make_path(cmake_build_dir, "cache.cmake"), "w") - if not cache_file then return nil, "Error creating CMake cache file in '" .. cmake_build_dir .. "'" end - - -- Fill in cache variables - for k,v in pairs(variables) do - cache_file:write("SET(" .. k .. " " .. sys.quote(v):gsub("\\+", "/") .. " CACHE STRING \"\" FORCE)\n") - end - - -- If user cache file is provided then append it - if cfg.cache_file ~= "" then - local user_cache = io.open(sys.abs_path(cfg.cache_file), "r") - if user_cache then - cache_file:write(user_cache:read("*all").."\n") - user_cache:close() - end - end - cache_file:close() - - src_dir = sys.abs_path(src_dir) - print("Building " .. sys.extract_name(src_dir) .. "...") - - -- set cmake cache command - local cache_command = cfg.cache_command - if cfg.debug then cache_command = cache_command .. " " .. cfg.cache_debug_options end - - -- set cmake build command - local build_command = cfg.build_command - if cfg.debug then build_command = build_command .. " " .. cfg.build_debug_options end - - -- set the cmake cache - local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cache_command .. " " .. sys.quote(src_dir)) - if not ok then return nil, "Error preloading the CMake cache script '" .. sys.make_path(cmake_build_dir, "cache.cmake") .. "'" end - - -- build with cmake - ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. build_command) - if not ok then return nil, "Error building with CMake in directory '" .. cmake_build_dir .. "'" end - - -- if this is only simulation, exit sucessfully, skipping the next actions - if cfg.simulate then - return true, "Simulated build and deployment of package '" .. pkg_name .. "' sucessfull." - end - - -- table to collect files installed in the components - info.files = {} - - -- install the components - for _, component in ipairs(cfg.components) do - local strip_option = "" - if not cfg.debug and component ~= "Library" then strip_option = cfg.strip_option end - - local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cfg.cmake .. " " .. strip_option .. " " ..cfg.install_component_command:gsub("#COMPONENT#", component)) - - if not ok then return nil, "Error when installing the component '" .. component .. "' with CMake in directory '" .. cmake_build_dir .. "'" end - - local install_mf = sys.make_path(cmake_build_dir, "install_manifest_" .. component .. ".txt") - local mf, err - local component_files = {} - - -- collect files installed in this component - if sys.exists(install_mf) then - mf, err = io.open(install_mf, "r") - if not mf then return nil, "Error when opening the CMake installation manifest '" .. install_mf .. "': " .. err end - for line in mf:lines() do - line = sys.check_separators(line) - local file = line:gsub(utils.escape_magic(deploy_dir .. sys.path_separator()), "") - table.insert(component_files, file) - end - mf:close() - - -- add list of component files to the 'dist.info' - if #component_files > 0 then info.files[component] = component_files end - end - end --- if bookmark == 0 then return nil, "Package did not install any files!" end - - -- test with ctest - if cfg.test then - print("Testing " .. sys.extract_name(src_dir) .. " ...") - ok = sys.exec("cd " .. sys.quote(deploy_dir) .. " && " .. cfg.test_command) - if not ok then return nil, "Error when testing the module '" .. pkg_name .. "' with CTest." end - end - - -- save modified 'dist.info' file - local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name) - sys.make_dir(pkg_distinfo_dir) - ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info")) - if not ok then return nil, err end - - -- clean up - if not cfg.debug then sys.delete(cmake_build_dir) end - - return true, "Package '" .. pkg_name .. "' successfully builded and deployed to '" .. deploy_dir .. "'." -end - --- Deploy binary package from 'pkg_dir' to 'deploy_dir' by copying. -function deploy_binary_pkg(pkg_dir, deploy_dir) - deploy_dir = deploy_dir or cfg.root_dir - - assert(type(pkg_dir) == "string", "package.deploy_binary_pkg: Argument 'pkg_dir' is not a string.") - assert(type(deploy_dir) == "string", "package.deploy_binary_pkg: Argument 'deploy_dir' is not a string.") - - pkg_dir = sys.abs_path(pkg_dir) - deploy_dir = sys.abs_path(deploy_dir) - - -- check for dist.info - local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info")) - if not info then return nil, "Error deploying package from '" .. pkg_dir .. "': it doesn't contain valid 'dist.info' file." end - local pkg_name = info.name .. "-" .. info.version - - -- if this is only simulation, exit sucessfully, skipping the next actions - if cfg.simulate then - return true, "Simulated deployment of package '" .. pkg_name .. "' sucessfull." - end - - -- copy all components of the module to the deploy_dir - for _, component in ipairs(cfg.components) do - if info.files[component] then - for _, file in ipairs(info.files[component]) do - local dest_dir = sys.make_path(deploy_dir, sys.parent_dir(file)) - - local ok, err = sys.make_dir(dest_dir) - if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot create directory '" .. dest_dir .. "': " .. err end - - ok, err = sys.copy(sys.make_path(pkg_dir, file), dest_dir) - if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot copy file '" .. file .. "' to the directory '" .. dest_dir .. "': " .. err end - end - end - end - - -- copy dist.info to register the module as installed - local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name) - sys.make_dir(pkg_distinfo_dir) - ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info")) - if not ok then return nil, err end - - return true, "Package '" .. pkg_name .. "' successfully deployed to '" .. deploy_dir .. "'." -end - --- Fetch package (table 'pkg') to download_dir. Return the original 'pkg' table --- with 'pkg.download_dir' containing path to the directory of the --- downloaded package. --- --- When optional 'suppress_printing' parameter is set to true, then messages --- for the user won't be printed during run of this function. --- --- If the 'pkg' already contains the information about download directory (pkg.download_dir), --- we assume the package was already downloaded there and won't download it again. -function fetch_pkg(pkg, download_dir, suppress_printing) - download_dir = download_dir or sys.current_dir() - suppress_printing = suppress_printing or false - assert(type(pkg) == "table", "package.fetch_pkg: Argument 'pkg' is not a table.") - assert(type(download_dir) == "string", "package.fetch_pkg: Argument 'download_dir' is not a string.") - assert(type(suppress_printing) == "boolean", "package.fetch_pkg: Argument 'suppress_printing' is not a boolean.") - assert(type(pkg.name) == "string", "package.fetch_pkg: Argument 'pkg.name' is not a string.") - assert(type(pkg.version) == "string", "package.fetch_pkg: Argument 'pkg.version' is not a string.") - - -- if the package is already downloaded don't download it again - if pkg.download_dir then return pkg end - - assert(type(pkg.path) == "string", "package.fetch_pkg: Argument 'pkg.path' is not a string.") - download_dir = sys.abs_path(download_dir) - - local pkg_full_name = pkg.name .. "-" .. pkg.version - local repo_url = pkg.path - local clone_dir = sys.abs_path(sys.make_path(download_dir, pkg_full_name)) - pkg.download_dir = clone_dir - - -- check if download_dir already exists, assuming the package was already downloaded - if sys.exists(sys.make_path(clone_dir, "dist.info")) then - if cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, clone_dir) then - if not suppress_printing then print("'" .. pkg_full_name .. "' already in cache, skipping downloading (use '-cache=false' to force download).") end - return pkg - else - sys.delete(sys.make_path(clone_dir)) - end - end - - local bin_tag = pkg.version .. "-" .. cfg.arch .. "-" .. cfg.type - local use_binary = false - - if cfg.binary then - -- check if binary version of the module for this arch & type available - local avail_tags, err = git.get_remote_tags(repo_url) - if not avail_tags then return nil, err end - - if utils.contains(avail_tags, bin_tag) then - use_binary = true - end - end - - -- init the git repository - local ok, err = git.create_repo(clone_dir) - if not ok then return nil, err end - - -- Fetch the desired ref (from the pkg's remote repo) and checkout into it. - - if use_binary then - - if not suppress_printing then print("Getting " .. pkg_full_name .. " (binary)...") end - - -- We fetch the binary tag. - local sha - if ok then sha, err = git.fetch_tag(clone_dir, repo_url, bin_tag) end - if sha then ok, err = git.checkout_sha(sha, clone_dir) end - - elseif cfg.source then - - if not suppress_printing then print("Getting " .. pkg_full_name .. " (source)...") end - - -- If we want the 'scm' version, we fetch the 'master' branch, otherwise - -- we fetch the tag, matching the desired package version. - if ok and pkg.version ~= "scm" then - local sha - sha, err = git.fetch_tag(clone_dir, repo_url, pkg.version) - if sha then ok, err = git.checkout_sha(sha, clone_dir) end - elseif ok then - local sha - sha, err = git.fetch_branch(clone_dir, repo_url, "master") - if sha then ok, err = git.checkout_sha(sha, clone_dir) end - end - - else - ok = false - if cfg.binary then - err = "Binary version of module not available and using source modules disabled." - else - err = "Using both binary and source modules disabled." - end - end - - if not ok then - -- clean up - if not cfg.debug then sys.delete(clone_dir) end - return nil, "Error fetching package '" .. pkg_full_name .. "' from '" .. pkg.path .. "' to '" .. download_dir .. "': " .. err - end - - -- delete '.git' directory - if not cfg.debug then sys.delete(sys.make_path(clone_dir, ".git")) end - - return pkg -end - --- Return table with information about available versions of 'package'. --- --- When optional 'suppress_printing' parameter is set to true, then messages --- for the user won't be printed during run of this function. -function retrieve_versions(package, manifest, suppress_printing) - suppress_printing = suppress_printing or false - assert(type(package) == "string", "package.retrieve_versions: Argument 'string' is not a string.") - assert(type(manifest) == "table", "package.retrieve_versions: Argument 'manifest' is not a table.") - assert(type(suppress_printing) == "boolean", "package.retrieve_versions: Argument 'suppress_printing' is not a boolean.") - - -- get package table - local pkg_name = depends.split_name_constraint(package) - local tmp_packages = depends.find_packages(pkg_name, manifest) - - if #tmp_packages == 0 then - return nil, "No suitable candidate for package '" .. package .. "' found." - else - package = tmp_packages[1] - end - - -- if the package's already downloaded, we assume it's desired to install the downloaded version - if package.download_dir then - local pkg_type = "binary" - if is_source_type(package.download_dir) then pkg_type = "source" end - if not suppress_printing then print("Using " .. package.name .. "-" .. package.version .. " (" .. pkg_type .. ") provided by " .. package.download_dir) end - return {package} - end - - if not suppress_printing then print("Finding out available versions of " .. package.name .. "...") end - - -- get available versions - local tags, err = git.get_remote_tags(package.path) - if not tags then return nil, "Error when retrieving versions of package '" .. package.name .. "': " .. err end - - -- filter out tags of binary packages - local versions = utils.filter(tags, function (tag) return tag:match("^[^%-]+%-?[^%-]*$") and true end) - - packages = {} - - -- create package information - for _, version in pairs(versions) do - pkg = {} - pkg.name = package.name - pkg.version = version - pkg.path = package.path - table.insert(packages, pkg) - end - - return packages -end - --- Return table with information from package's dist.info and path to downloaded --- package. Optional argument 'deploy_dir' is used just as a temporary --- place to place the downloaded packages into. --- --- When optional 'suppress_printing' parameter is set to true, then messages --- for the user won't be printed during the execution of this function. -function retrieve_pkg_info(package, deploy_dir, suppress_printing) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(package) == "table", "package.retrieve_pkg_info: Argument 'package' is not a table.") - assert(type(deploy_dir) == "string", "package.retrieve_pkg_info: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - local tmp_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir)) - - -- download the package - local fetched_pkg, err = fetch_pkg(package, tmp_dir, suppress_printing) - if not fetched_pkg then return nil, "Error when retrieving the info about '" .. package.name .. "': " .. err end - - -- load information from 'dist.info' - local info, err = mf.load_distinfo(sys.make_path(fetched_pkg.download_dir, "dist.info")) - if not info then return nil, err end - - -- add other attributes - if package.path then info.path = package.path end - if package.was_scm_version then info.was_scm_version = package.was_scm_version end - - -- set default arch/type if not explicitly stated and package is of source type - if is_source_type(fetched_pkg.download_dir) then - info = ensure_source_arch_and_type(info) - elseif not (info.arch and info.type) then - return nil, fetched_pkg.download_dir .. ": binary package missing arch or type in 'dist.info'." - end - - return info, fetched_pkg.download_dir -end - --- Return manifest, augmented with info about all available versions --- of package 'pkg'. Optional argument 'deploy_dir' is used just as a temporary --- place to place the downloaded packages into. --- Optional argument 'installed' is manifest of all installed packages. When --- specified, info from installed packages won't be downloaded from repo, --- but the dist.info from installed package will be used. -function get_versions_info(pkg, manifest, deploy_dir, installed) - deploy_dir = deploy_dir or cfg.root_dir - assert(type(pkg) == "string", "package.get_versions_info: Argument 'pkg' is not a string.") - assert(type(manifest) == "table", "package.get_versions_info: Argument 'manifest' is not a table.") - assert(type(deploy_dir) == "string", "package.get_versions_info: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - -- find all available versions of package - local versions, err = retrieve_versions(pkg, manifest) - if not versions then return nil, err end - - -- collect info about all retrieved versions - local infos = {} - for _, version in pairs(versions) do - - local info, path_or_err - local installed_version = {} - - -- find out whether this 'version' is installed so we can use it's dist.info - if type(installed) == "table" then installed_version = depends.find_packages(version.name .. "-" .. version.version, installed) end - - -- get info - if #installed_version > 0 then - print("Using dist.info from installed " .. version.name .. "-" .. version.version) - info = installed_version[1] - info.path = version.path - info.from_installed = true -- flag that dist.info of installed package was used - else - info, path_or_err = retrieve_pkg_info(version, deploy_dir) - if not info then return nil, path_or_err end - sys.delete(path_or_err) - end - table.insert(infos, info) - end - - -- found and add an implicit 'scm' version - local pkg_name = depends.split_name_constraint(pkg) - local found = depends.find_packages(pkg_name, manifest) - if #found == 0 then return nil, "No suitable candidate for package '" .. pkg .. "' found." end - local scm_info, path_or_err = retrieve_pkg_info({name = pkg_name, version = "scm", path = found[1].path}) - if not scm_info then return nil, path_or_err end - sys.delete(path_or_err) - scm_info.version = "scm" - table.insert(infos, scm_info) - - local tmp_manifest = utils.deepcopy(manifest) - - -- add collected info to the temp. manifest, replacing existing tables - for _, info in pairs(infos) do - local already_in_manifest = false - -- find if this version is already in manifest - for idx, pkg in ipairs(tmp_manifest) do - -- if yes, replace it - if pkg.name == info.name and pkg.version == info.version then - tmp_manifest[idx] = info - already_in_manifest = true - break - end - end - -- if not, just normally add to the manifest - if not already_in_manifest then - table.insert(tmp_manifest, info) - end - end - - return tmp_manifest -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/sys.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/sys.lua deleted file mode 100644 index 803df12..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/sys.lua +++ /dev/null @@ -1,386 +0,0 @@ --- System functions - -module ("dist.sys", package.seeall) - -local cfg = require "dist.config" -local utils = require "dist.utils" -local lfs = require "lfs" - --- Return the path separator according to the platform. -function path_separator() - if cfg.arch == "Windows" then - return "\\" - else - return "/" - end -end - --- Return path with wrong separators replaced with the right ones. -function check_separators(path) - assert(type(path) == "string", "sys.check_separators: Argument 'path' is not a string.") - if cfg.arch == "Windows" then - return path:gsub("/", "\\") - else - return path - end -end - --- Return the path with the unnecessary trailing separator removed. -function remove_trailing(path) - assert(type(path) == "string", "sys.remove_trailing: Argument 'path' is not a string.") - if path:sub(-1) == path_separator() and not is_root(path) then path = path:sub(1,-2) end - return path -end - --- Return the path with the all occurences of '/.' or '\.' (representing --- the current directory) removed. -function remove_curr_dir_dots(path) - assert(type(path) == "string", "sys.remove_curr_dir_dots: Argument 'path' is not a string.") - while path:match(path_separator() .. "%." .. path_separator()) do -- match("/%./") - path = path:gsub(path_separator() .. "%." .. path_separator(), path_separator()) -- gsub("/%./", "/") - end - return path:gsub(path_separator() .. "%.$", "") -- gsub("/%.$", "") -end - --- Return string argument quoted for a command line usage. -function quote(argument) - assert(type(argument) == "string", "sys.quote: Argument 'argument' is not a string.") - - -- TODO: This seems like a not very nice hack. Why is it needed? - -- Wouldn't it be better to fix the problem where it originates? - -- replace '/' path separators for '\' on Windows - if cfg.arch == "Windows" and argument:match("^[%u%U.]?:?[/\\].*") then - argument = argument:gsub("//","\\"):gsub("/","\\") - end - - -- Windows doesn't recognize paths starting with two slashes or backslashes - -- so we double every backslash except for the first one - if cfg.arch == "Windows" and argument:match("^[/\\].*") then - local prefix = argument:sub(1,1) - argument = argument:sub(2):gsub("\\", "\\\\") - argument = prefix .. argument - else - argument = argument:gsub("\\", "\\\\") - end - argument = argument:gsub('"', '\\"') - - return '"' .. argument .. '"' -end - --- Run the system command (in current directory). --- Return true on success, nil on fail and log string. --- When optional 'force_verbose' parameter is true, then the output will be shown --- even when not in debug or verbose mode. -function exec(command, force_verbose) - force_verbose = force_verbose or false - assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.") - assert(type(force_verbose) == "boolean", "sys.exec: Argument 'force_verbose' is not a boolean.") - - if not (cfg.verbose or cfg.debug or force_verbose) then - if cfg.arch == "Windows" then - command = command .. " > NUL 2>&1" - else - command = command .. " > /dev/null 2>&1" - end - end - - if cfg.debug then print("Executing the command: " .. command) end - local ok, str, status = os.execute(command) - - -- os.execute returned values on failure are: - -- nil or true, "exit", n or true, "signal", n for lua >= 5.2 - -- status ~= 0 for lua 5.x < 5.2 - if ok == nil or (str == "exit" and status ~= 0) or str == "signal" or (ok ~= 0 and ok ~= true) then - return nil, "Error when running the command: " .. command - else - return true, "Sucessfully executed the command: " .. command - end -end - --- Execute the 'command' and returns its output as a string. -function capture_output(command) - assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.") - - local executed, err = io.popen(command, "r") - if not executed then return nil, "Error running the command '" .. command .. "':" .. err end - - local captured, err = executed:read("*a") - if not captured then return nil, "Error reading the output of command '" .. command .. "':" .. err end - - executed:close() - return captured -end - --- Return whether the path is a root. -function is_root(path) - assert(type(path) == "string", "sys.is_root: Argument 'path' is not a string.") - return utils.to_boolean(path:find("^[a-zA-Z]:[/\\]$") or path:find("^[/\\]$")) -end - --- Return whether the path is absolute. -function is_abs(path) - assert(type(path) == "string", "sys.is_abs: Argument 'path' is not a string.") - return utils.to_boolean(path:find("^[a-zA-Z]:[/\\].*$") or path:find("^[/\\].*$")) -end - --- Return whether the specified file or directory exists. -function exists(path) - assert(type(path) == "string", "sys.exists: Argument 'path' is not a string.") - local attr, err = lfs.attributes(path) - return utils.to_boolean(attr), err -end - --- Return whether the 'file' exists and is a file. -function is_file(file) - assert(type(file) == "string", "sys.is_file: Argument 'file' is not a string.") - return lfs.attributes(file, "mode") == "file" -end - --- Return whether the 'dir' exists and is a directory. -function is_dir(dir) - assert(type(dir) == "string", "sys.is_dir: Argument 'dir' is not a string.") - return lfs.attributes(dir, "mode") == "directory" -end - --- Return the current working directory -function current_dir() - local dir, err = lfs.currentdir() - if not dir then return nil, err end - return dir -end - --- Return an iterator over the directory 'dir'. --- If 'dir' doesn't exist or is not a directory, return nil and error message. -function get_directory(dir) - dir = dir or current_dir() - assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.") - if is_dir(dir) then - return lfs.dir(dir) - else - return nil, "Error: '".. dir .. "' is not a directory." - end -end - --- Extract file or directory name from its path. -function extract_name(path) - assert(type(path) == "string", "sys.extract_name: Argument 'path' is not a string.") - if is_root(path) then return path end - - path = remove_trailing(path) - path = path:gsub("^.*" .. path_separator(), "") - return path -end - --- Return parent directory of the 'path' or nil if there's no parent directory. --- If 'path' is a path to file, return the directory the file is in. -function parent_dir(path) - assert(type(path) == "string", "sys.parent_dir: Argument 'path' is not a string.") - path = remove_curr_dir_dots(path) - path = remove_trailing(path) - - local dir = path:gsub(utils.escape_magic(extract_name(path)) .. "$", "") - if dir == "" then - return nil - else - return make_path(dir) - end -end - --- Returns the table of all parent directories of 'path' up to the directory --- specified by 'boundary_path' (exclusive). -function parents_up_to(path, boundary_path) - assert(type(path) == "string", "sys.parents_up_to: Argument 'path' is not a string.") - assert(type(boundary_path) == "string", "sys.parents_up_to: Argument 'boundary_path' is not a string.") - boundary_path = remove_trailing(boundary_path) - - -- helper function to recursively collect the parent directories - local function collect_parents(_path, _parents) - local _parent = parent_dir(_path) - if _parent and _parent ~= boundary_path then - table.insert(_parents, _parent) - return collect_parents(_parent, _parents) - else - return _parents - end - end - - return collect_parents(path, {}) -end - --- Compose path composed from specified parts or current --- working directory when no part specified. -function make_path(...) - -- arg is deprecated in lua 5.2 in favor of table.pack we mimic here - local arg = {n=select('#',...),...} - local parts = arg - assert(type(parts) == "table", "sys.make_path: Argument 'parts' is not a table.") - - local path, err - if parts.n == 0 then - path, err = current_dir() - else - path, err = table.concat(parts, path_separator()) - end - if not path then return nil, err end - - -- squeeze repeated occurences of a file separator - path = path:gsub(path_separator() .. "+", path_separator()) - - -- remove unnecessary trailing path separator - path = remove_trailing(path) - - return path -end - --- Return absolute path from 'path' -function abs_path(path) - assert(type(path) == "string", "sys.get_abs_path: Argument 'path' is not a string.") - if is_abs(path) then return path end - - local cur_dir, err = current_dir() - if not cur_dir then return nil, err end - - return make_path(cur_dir, path) -end - --- Returns path to the temporary directory of OS. -function tmp_dir() - return os.getenv("TMPDIR") or os.getenv("TEMP") or os.getenv("TMP") or "/tmp" -end - --- Returns temporary file (or directory) path (with optional prefix). -function tmp_name(prefix) - prefix = prefix or "" - assert(type(prefix) == "string", "sys.tmp_name: Argument 'prefix' is not a string.") - return make_path(tmp_dir(), prefix .. "luadist_" .. utils.rand(10000000000)) -end - --- Return table of all paths in 'dir' -function get_file_list(dir) - dir = dir or current_dir() - assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.") - if not exists(dir) then return nil, "Error getting file list of '" .. dir .. "': directory doesn't exist." end - - local function collect(path, all_paths) - for item in get_directory(path) do - - local item_path = make_path(path, item) - local _, last = item_path:find(dir .. path_separator(), 1, true) - local path_to_insert = item_path:sub(last + 1) - - if is_file(item_path) then - table.insert(all_paths, path_to_insert) - elseif is_dir(item_path) and item ~= "." and item ~= ".." then - table.insert(all_paths, path_to_insert) - collect(item_path, all_paths) - end - end - end - - local all_paths = {} - collect(dir, all_paths) - - return all_paths -end - --- Return time of the last modification of 'file'. -function last_modification_time(file) - assert(type(file) == "string", "sys.last_modification_time: Argument 'file' is not a string.") - return lfs.attributes(file, "modification") -end - --- Return the current time (in seconds since epoch). -function current_time() - return os.time() -end - --- Change the current working directory and return 'true' and previous working --- directory on success and 'nil' and error message on error. -function change_dir(dir_name) - assert(type(dir_name) == "string", "sys.change_dir: Argument 'dir_name' is not a string.") - local prev_dir = current_dir() - local ok, err = lfs.chdir(dir_name) - if ok then - return ok, prev_dir - else - return nil, err - end -end - --- Make a new directory, making also all of its parent directories that doesn't exist. -function make_dir(dir_name) - assert(type(dir_name) == "string", "sys.make_dir: Argument 'dir_name' is not a string.") - if exists(dir_name) then - return true - else - local par_dir = parent_dir(dir_name) - if par_dir then - local ok, err = make_dir(par_dir) - if not ok then return nil, err end - end - return lfs.mkdir(dir_name) - end -end - --- Move file (or directory) to the destination directory -function move_to(file_or_dir, dest_dir) - assert(type(file_or_dir) == "string", "sys.move_to: Argument 'file_or_dir' is not a string.") - assert(type(dest_dir) == "string", "sys.move_to: Argument 'dest_dir' is not a string.") - assert(is_dir(dest_dir), "sys.move_to: Destination '" .. dest_dir .."' is not a directory.") - - -- Extract file/dir name from its path - local file_or_dir_name = extract_name(file_or_dir) - - return os.rename(file_or_dir, make_path(dest_dir, file_or_dir_name)) -end - --- rename file (or directory) to the new name. -function rename(file, new_name) - assert(type(file) == "string", "sys.rename: Argument 'file' is not a string.") - assert(type(new_name) == "string", "sys.rename: Argument 'new_name' is not a string.") - assert(not exists(new_name), "sys.rename: desired filename already exists.") - - return os.rename(file, new_name) -end - --- Copy 'source' to the destination directory 'dest_dir'. --- If 'source' is a directory, then recursive copying is used. --- For non-recursive copying of directories use the make_dir() function. -function copy(source, dest_dir) - assert(type(source) == "string", "sys.copy: Argument 'file_or_dir' is not a string.") - assert(type(dest_dir) == "string", "sys.copy: Argument 'dest_dir' is not a string.") - assert(is_dir(dest_dir), "sys.copy: destination '" .. dest_dir .."' is not a directory.") - - if cfg.arch == "Windows" then - if is_dir(source) then - make_dir(make_path(dest_dir, extract_name(source))) - return exec("xcopy /E /I /Y /Q " .. quote(source) .. " " .. quote(dest_dir .. "\\" .. extract_name(source))) - else - return exec("copy /Y " .. quote(source) .. " " .. quote(dest_dir)) - end - else - if is_dir(source) then - return exec("cp -fRH " .. quote(source) .. " " .. quote(dest_dir)) - else - return exec("cp -fH " .. quote(source) .. " " .. quote(dest_dir)) - end - end -end - --- Delete the specified file or directory -function delete(path) - assert(type(path) == "string", "sys.delete: Argument 'path' is not a string.") - assert(is_abs(path), "sys.delete: Argument 'path' is not an absolute path.") - - if cfg.arch == "Windows" then - if not exists(path) then - return true - elseif is_file(path) then - return os.remove(path) - else - return exec("rd /S /Q " .. quote(path)) - end - else - return exec("rm -rf " .. quote(path)) - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/utils.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/utils.lua deleted file mode 100644 index 392654c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/dist/utils.lua +++ /dev/null @@ -1,151 +0,0 @@ --- System functions - -module ("dist.utils", package.seeall) - -local sys = require "dist.sys" - --- Returns a deep copy of 'table' with reference to the same metadata table. --- Source: http://lua-users.org/wiki/CopyTable -function deepcopy(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - return _copy(object) -end - --- Return deep copy of table 'array', containing only items for which 'predicate_fn' returns true. -function filter(array, predicate_fn) - assert(type(array) == "table", "utils.filter: Argument 'array' is not a table.") - assert(type(predicate_fn) == "function", "utils.filter: Argument 'predicate_fn' is not a function.") - local filtered = {} - for _,v in pairs(array) do - if predicate_fn(v) == true then table.insert(filtered, deepcopy(v)) end - end - return filtered -end - --- Return deep copy of table 'array', sorted according to the 'compare_fn' function. -function sort(array, compare_fn) - assert(type(array) == "table", "utils.sort: Argument 'array' is not a table.") - assert(type(compare_fn) == "function", "utils.sort: Argument 'compare_fn' is not a function.") - local sorted = deepcopy(array) - table.sort(sorted, compare_fn) - return sorted -end - --- Return whether the 'value' is in the table 'tbl'. -function contains(tbl, value) - assert(type(tbl) == "table", "utils.contains: Argument 'tbl' is not a table.") - for _,v in pairs(tbl) do - if v == value then return true end - end - return false -end - --- Return single line string consisting of values in 'tbl' separated by comma. --- Used for printing the dependencies/provides/conflicts. -function table_tostring(tbl, label) - assert(type(tbl) == "table", "utils.table_tostring: Argument 'tbl' is not a table.") - local str = "" - for k,v in pairs(tbl) do - if type(v) == "table" then - str = str .. table_tostring(v, k) - else - if label ~= nil then - str = str .. tostring(v) .. " [" .. tostring(label) .. "]" .. ", " - else - str = str .. tostring(v) .. ", " - end - end - end - return str -end - --- Return table made up from values of the string, separated by separator. -function make_table(str, separator) - assert(type(str) == "string", "utils.make_table: Argument 'str' is not a string.") - assert(type(separator) == "string", "utils.make_table: Argument 'separator' is not a string.") - - local tbl = {} - for val in str:gmatch("(.-)" .. separator) do - table.insert(tbl, val) - end - local last_val = str:gsub(".-" .. separator, "") - if last_val and last_val ~= "" then - table.insert(tbl, last_val) - end - return tbl -end - --- Return whether the 'cache_timeout' for 'file' has expired. -function cache_timeout_expired(cache_timeout, file) - assert(type(cache_timeout) == "number", "utils.cache_timeout_expired: Argument 'cache_timeout' is not a number.") - assert(type(file) == "string", "utils.cache_timeout_expired: Argument 'file' is not a string.") - return sys.last_modification_time(file) + cache_timeout < sys.current_time() -end - --- Return the string 'str', with all magic (pattern) characters escaped. -function escape_magic(str) - assert(type(str) == "string", "utils.escape: Argument 'str' is not a string.") - local escaped = str:gsub('[%-%.%+%[%]%(%)%^%%%?%*%^%$]','%%%1') - return escaped -end - --- Return the boolean representation of an 'arg'. -function to_boolean(arg) - return not not arg -end - - -math.randomseed(os.time()) - --- Return pseudo-random number in range [0, 1], [1, n] or [n, m]. -function rand(...) - return math.random(...) -end - --- Perform check of system dependency, which isn't provided in the LuaDist --- installation itself and if it is missing, print instructions how --- to install it. The 'command' is used for testing, 'name' when printing --- information to the user. -function system_dependency_available(name, command) - assert(type(name) == "string", "utils.system_dependency_available: Argument 'name' is not a string.") - assert(type(command) == "string", "utils.system_dependency_available: Argument 'command' is not a string.") - - if not sys.exec(command) then - print("Error: command '" .. name .. "' not found on system. See installation instructions at\nhttps://github.com/LuaDist/Repository/wiki/Installation-of-System-Dependencies") - return false - end - - return true -end - --- Obtain LuaDist location by checking available package locations -function get_luadist_location() - local paths = {} - local path = package.path:gsub("([^;]+)", function(c) table.insert(paths, c) end) - - for _, path in pairs(paths) do - if (sys.is_abs(path) and path:find("[/\\]lib[/\\]lua[/\\]%?.lua$")) then - -- Remove path to lib/lua - path = path:gsub("[/\\]lib[/\\]lua[/\\]%?.lua$", "") - -- Clean the path up a bit - path = path:gsub("[/\\]bin[/\\]%.[/\\]%.%.", "") - path = path:gsub("[/\\]bin[/\\]%.%.", "") - return path - end - end - return nil -end - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git.lua deleted file mode 100644 index 96b4058..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git.lua +++ /dev/null @@ -1,5 +0,0 @@ -require 'git.util' -require 'git.objects' -require 'git.pack' -require 'git.repo' -require 'git.protocol' diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/objects.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/objects.lua deleted file mode 100644 index 85de9b0..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/objects.lua +++ /dev/null @@ -1,121 +0,0 @@ -local util = require 'git.util' - -local assert, next, io, print, os, type, string, pairs, tostring = - assert, next, io, print, os, type, string, pairs, tostring -local join_path = git.util.join_path - -local require = require - -local isPosix = package.config:sub(1,1) == '/' -- wild guess - -module(...) - -Commit = {} -Commit.__index = Commit - -function Commit:tree() - return self.repo:tree(self.tree_sha) -end - -function Commit:checkout(path) - assert(path, 'path argument missing') - self:tree():checkoutTo(path) -end - - -Tree = {} -Tree.__index = function (t,k) - if Tree[k] then return Tree[k] end - return t:entry(k) -end - -function Tree:entries() - return function(t, n) - local n, entry = next(t, n) - if entry then - local object - if entry.type == 'tree' then - object = self.repo:tree(entry.id) - elseif entry.type == 'blob' then - object = self.repo:blob(entry.id) - object.mode = entry.mode - elseif entry.type == 'commit' then - -- this is possibly a commit in a submodule, - -- do not retrieve it from current repo - object = entry - else - error('Unknown entry type: ' .. entry.type) - end - return n, entry.type, object - end - end, self._entries -end - -function Tree:entry(n) - local e = self._entries[n] - if not e then return end - if e.type == 'tree' then - return self.repo:tree(e.id) - elseif e.type == 'commit' then - return self.repo:commit(e.id) - elseif e.type == 'blob' then - return self.repo:blob(e.id) - else - error('Unknown entry type: ' .. e.type) - end -end - -function Tree:walk(func, path) - path = path or '.' - assert(type(func) == "function", "argument is not a function") - local function walk(tree, path) - for name, type, entry in tree:entries() do - local entry_path = join_path(path, name) - func(entry, entry_path, type) - - if type == "tree" then - walk(entry, entry_path) - end - end - end - walk(self, path) -end - -function Tree:checkoutTo(path) - util.make_dir(path) - self:walk(function (entry, entry_path, type) - if type == 'tree' then - util.make_dir(entry_path) - elseif type == 'blob' then - local out = assert(io.open(entry_path, 'wb')) - out:write(entry:content()) - out:close() - if isPosix then - local mode = entry.mode:sub(-3,-1) -- fixme: is this ok? - local cmd = 'chmod '..mode..' "'..entry_path..'"' - os.execute(cmd) - end - elseif type == 'commit' then - -- this is a submodule referencing a commit, - -- make a directory for it - util.make_dir(entry_path) - else - error('Unknown entry type: ', type) - end - end, path) -end - -Blob = {} -Blob.__index = Blob - -function Blob:content() - if self.stored then - local f = self.repo:raw_object(self.id) - local ret = f:read('*a') or "" - f:close() - return ret - else - return self.data - end -end - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/pack.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/pack.lua deleted file mode 100644 index f1597c3..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/pack.lua +++ /dev/null @@ -1,316 +0,0 @@ -local io = io -local core = require 'git.core' - -local assert, pcall, print, select, setmetatable, string, type, unpack = - assert, pcall, print, select, setmetatable, string, type, unpack - -local ord = string.byte -local fmt = string.format -local concat, insert = table.concat, table.insert - -local band = core.band -local rshift, lshift = core.rshift, core.lshift - -local to_hex = git.util.to_hex -local from_hex = git.util.from_hex -local object_sha = git.util.object_sha -local binary_sha = git.util.binary_sha -local readable_sha = git.util.readable_sha -local tmpfile = git.util.tmpfile -local reader = git.util.reader - -module(...) - --- read git/Documentation/technical/pack-format.txt for some inspiration - --- 1 = commit, 2 = tree ... -local types = {'commit', 'tree', 'blob', 'tag', '???', 'ofs_delta', 'ref_delta'} - --- read a 4 byte unsigned integer stored in network order -local function read_int(f) - local s = f:read(4) - local a,b,c,d = s:byte(1,4) - return a*256^3 + b*256^2 + c*256 + d -end - --- read in the type and file length -local function read_object_header(f) - local b = ord(f:read(1)) - local type = band(rshift(b, 4), 0x7) - local len = band(b, 0xF) - local ofs = 0 - while band(b, 0x80) ~= 0 do - b = ord(f:read(1)) - len = len + lshift(band(b, 0x7F), ofs * 7 + 4) - ofs = ofs + 1 - end - return len, type -end - --- reads in the delta header and returns the offset where original data is stored -local function read_delta_header(f) - local b = ord(f:read(1)) - local offset = band(b, 0x7F) - while band(b, 0x80) ~= 0 do - offset = offset + 1 - b = ord(f:read(1)) - offset = lshift(offset, 7) + band(b, 0x7F) - end - return offset -end - --- read just enough of file `f` to uncompress `size` bytes -local function uncompress_by_len(f, size) - local z = core.inflate() - local chunks = {} - local CHUNK_SIZE = 1024 - local curr_pos = f:seek() - local inflated, eof, total - -- read until end of zlib-compresed stream - while not eof do - local data = f:read(CHUNK_SIZE) - inflated, eof, total = z(data) - insert(chunks, inflated) - end - -- repair the current position in stream - f:seek('set', curr_pos + total) - return concat(chunks) -end - --- uncompress the object from the current location in `f` -local function unpack_object(f, len, type) - local data = uncompress_by_len(f, len) - return data, len, type -end - --- returns a size value encoded in delta data -local function delta_size(f) - local size = 0 - local i = 0 - repeat - local b = ord(f:read(1)) - size = size + lshift(band(b, 0x7F), i) - i = i + 7 - until band(b, 0x80) == 0 - return size -end - --- returns a patched object from string `base` according to `delta` data -local function patch_object(base, delta, base_type) - -- insert delta codes into temporary file - local df = reader(delta) - - -- retrieve original and result size (for checks) - local orig_size = delta_size(df) - assert(#base == orig_size, fmt('#base(%d) ~= orig_size(%d)', #base, orig_size)) - - local result_size = delta_size(df) - local size = result_size - - local result = {} - - -- process the delta codes - local cmd = df:read(1) - while cmd do - cmd = ord(cmd) - if cmd == 0 then - error('unexpected delta code 0') - elseif band(cmd, 0x80) ~= 0 then -- copy a selected part of base data - local cp_off, cp_size = 0, 0 - -- retrieve offset - if band(cmd, 0x01) ~= 0 then cp_off = ord(df:read(1)) end - if band(cmd, 0x02) ~= 0 then cp_off = cp_off + ord(df:read(1))*256 end - if band(cmd, 0x04) ~= 0 then cp_off = cp_off + ord(df:read(1))*256^2 end - if band(cmd, 0x08) ~= 0 then cp_off = cp_off + ord(df:read(1))*256^3 end - -- retrieve size - if band(cmd, 0x10) ~= 0 then cp_size = ord(df:read(1)) end - if band(cmd, 0x20) ~= 0 then cp_size = cp_size + ord(df:read(1))*256 end - if band(cmd, 0x40) ~= 0 then cp_size = cp_size + ord(df:read(1))*256^2 end - if cp_size == 0 then cp_size = 0x10000 end - if cp_off + cp_size > #base or cp_size > size then break end - -- get the data and append it to result - local data = base:sub(cp_off + 1, cp_off + cp_size) - insert(result, data) - size = size - cp_size - else -- insert new data - if cmd > size then break end - local data = df:read(cmd) - insert(result, data) - size = size - cmd - end - cmd = df:read(1) - end - - df:close() - - result = concat(result) - assert(#result == result_size, fmt('#result(%d) ~= result_size(%d)', #result, result_size)) - return result, result_size, base_type -end - -Pack = {} -Pack.__index = Pack - --- read an object from the current location in pack, or from a specific `offset` --- if specified -function Pack:read_object(offset, ignore_data) - local f = self.pack_file - if offset then - f:seek('set', offset) - end - local curr_pos = f:seek() - - local len, type = read_object_header(f) - if type < 5 then -- commit, tree, blob, tag - return unpack_object(f, len, type) - elseif type == 6 then -- ofs_delta - local offset = read_delta_header(f) - local delta_data = uncompress_by_len(f, len) - if not ignore_data then - -- the offset is negative from the current location - local base, base_len, base_type = self:read_object(curr_pos - offset) - return patch_object(base, delta_data, base_type) - end - elseif type == 7 then -- ref_delta - local sha = f:read(20) - local delta_data = uncompress_by_len(f, len) - if not ignore_data then - -- lookup the object in the pack by sha - -- FIXME: maybe lookup in repo/other packs - local base_offset = self.index[binary_sha(sha)] - local base, base_len, base_type = self:read_object(base_offset) - return patch_object(base, delta_data, base_type) - end - else - error('unknown object type: '..type) - end -end - --- returns true if this pack contains the given object -function Pack:has_object(sha) - return self.index[binary_sha(sha)] ~= nil -end - --- if the object name `sha` exists in the pack, returns a temporary file with the --- object content, length and type, otherwise returns nil -function Pack:get_object(sha) - local offset = self.index[binary_sha(sha)] - if not offset then - print('!!! Failed to find object', readable_sha(sha)) - end - - local data, len, type = self:read_object(offset) - print(readable_sha(sha), len, type, data) - local f = tmpfile() - f:write(data) - f:seek('set', 0) - - return f, len, types[type] -end - -function Pack:unpack(repo) - for i=1, self.nobjects do - local offset = self.offsets[i] - local data, len, type = self:read_object(offset) - repo:store_object(data, len, types[type]) - end -end - --- parses the index -function Pack:parse_index(index_file) - local f = index_file - - local head = f:read(4) - assert(head == '\255tOc', "Incorrect header: " .. head) - local version = read_int(f) - assert(version == 2, "Incorrect version: " .. version) - - -- first the fanout table (how many objects are in the index, whose - -- first byte is below or equal to i) - local fanout = {} - for i=0, 255 do - local nobjs = read_int(f) - fanout[i] = nobjs - end - - -- the last element in fanout is the number of all objects in index - local count = fanout[255] - - -- then come the sorted object names (=sha hash) - local tmp = {} - for i=1,count do - local sha = f:read(20) - tmp[i] = { sha = sha } - end - - -- then the CRCs (assume ok, skip them) - for i=1, count do - local crc = f:read(4) - end - - -- then come the offsets - read just the 32bit ones, does not handle packs > 2G - for i=1, count do - local offset = read_int(f) - tmp[i].offset = offset - end - - -- construct the lookup table - local lookup = {} - for i=1, count do - lookup[tmp[i].sha] = tmp[i].offset - end - self.index = lookup -end - --- constructs the index/offsets if the index file is missing -function Pack:construct_index(path) - local index = {} - for i=1, self.nobjects do - local offset = self.offsets[i] - local data, len, type = self:read_object(offset) - local sha = object_sha(data, len, types[type]) - index[binary_sha(sha)] = offset - end - self.index = index -end - -function Pack:close() - self.pack_file:close() -end - -function Pack.open(path) - local fp = assert(io.open(path, 'rb')) -- stays open - - -- read the pack header - local head = fp:read(4) - assert(head == 'PACK', "Incorrect header: " .. head) - local version = read_int(fp) - assert(version == 2, "Incorrect version: " .. version) - local nobj = read_int(fp) - - local pack = setmetatable({ - offsets = {}, - nobjects = nobj, - pack_file = fp, - }, Pack) - - -- fill the offsets by traversing through the pack - for i=1,nobj do - pack.offsets[i] = fp:seek() - -- ignore the object data, we only need the offset in the pack - pack:read_object(nil, true) - end - - -- read the index - local fi = io.open((path:gsub('%.pack$', '.idx')), 'rb') - if fi then - pack:parse_index(fi) - fi:close() - else - pack:construct_index(path) - end - - return pack -end - -return Pack \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/protocol.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/protocol.lua deleted file mode 100644 index 7bad2e2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/protocol.lua +++ /dev/null @@ -1,188 +0,0 @@ -local socket = require 'socket' -local urllib = require 'socket.url' -local lfs = require 'lfs' - -local Repo = git.repo.Repo -local Pack = git.pack.Pack -local join_path = git.util.join_path -local parent_dir = git.util.parent_dir -local make_dir = git.util.make_dir -local correct_separators = git.util.correct_separators - -local assert, error, getmetatable, io, os, pairs, print, require, string, tonumber = - assert, error, getmetatable, io, os, pairs, print, require, string, tonumber - -local _VERSION, newproxy = _VERSION, newproxy - -module(...) - -local GIT_PORT = 9418 - -local function git_connect(host) - local sock = assert(socket.connect(host, GIT_PORT)) - local gitsocket = {} - - function gitsocket:send(data) - if not data then -- flush packet - sock:send('0000') - else - local len = #data + 4 - len = string.format("%04x", len) - assert(sock:send(len .. data)) - end - end - - function gitsocket:receive() - local len = assert(sock:receive(4)) - len = tonumber(len, 16) - if len == 0 then return end -- flush packet - local data = assert(sock:receive(len - 4)) - return data - end - - function gitsocket:close() - sock:close() - end - - return gitsocket -end - -local function addFinalizer(object, finalizer) - if _VERSION <= "Lua 5.1" then - local gc = newproxy(true) - getmetatable(gc).__gc = finalizer - object.__gc = gc - else - local mt = getmetatable(object) - if mt then mt.__gc = finalizer - else setmetatable(object, {__gc = finalizer}) - end - end -end - -local function git_fetch(host, path, repo, head, supress_progress) - local s = git_connect(host) - s:send('git-upload-pack '..path..'\0host='..host..'\0') - - local refs, refsbyname = {}, {} - repeat - local ref = s:receive() - if ref then - local sha, name = ref:sub(1,40), ref:sub(42, -2) - refs[sha] = name - refsbyname[name] = sha - end - until not ref - - local wantedSha - local headsha = head and refsbyname[head] - - for sha, ref in pairs(refs) do - -- we implicitly want this ref - local wantObject = true - -- unless we ask for a specific head - if headsha then - if sha ~= headsha then - wantObject = false - else - wantedSha = sha - end - end - -- or we already have it - if repo and repo:has_object(sha) then - wantObject = false - end - if wantObject then - s:send('want '..sha..' multi_ack_detailed side-band-64k ofs-delta\n') - end - end - - if head and not wantedSha then - error("Server does not have "..head) - end - - s:send('deepen 1') - s:send() - while s:receive() do end - s:send('done\n') - - assert(s:receive() == "NAK\n") - - local packname = os.tmpname() .. '.pack' - local packfile = assert(io.open(packname, 'wb')) - repeat - local got = s:receive() - if got then - -- get sideband channel, 1=pack data, 2=progress, 3=error - local cmd = string.byte(got:sub(1,1)) - local data = got:sub(2) - if cmd == 1 then - packfile:write(data) - elseif cmd == 2 then - if not supress_progress then io.write(data) end - else - error(data) - end - end - until not got - - packfile:close() - s:close() - - local pack = Pack.open(packname) - if repo then - pack:unpack(repo) - repo.isShallow = true - if wantedSha then - local headfile = correct_separators(join_path(repo.dir, head)) - assert(make_dir(parent_dir(headfile))) - local f = assert(io.open(headfile, 'wb')) - f:write(wantedSha) - f:close() - end - end - - addFinalizer(pack, function() - os.remove(packname) - end) - - return pack, wantedSha -end - -function fetch(url, repo, head, supress_progress) - if repo then assert(getmetatable(repo) == Repo, "arg #2 is not a repository") end - url = urllib.parse(url) - if url.scheme == 'git' then - local pack, sha = git_fetch(url.host, url.path, repo, head, supress_progress) - return pack, sha - else - error('unsupported scheme: '..url.scheme) - end -end - -function remotes(url) - -- TODO: refactor common code - url = assert(urllib.parse(url)) - - if url.scheme ~= 'git' then - error('unsupported scheme: '..url.scheme) - end - - local host, path = url.host, url.path - - local s = git_connect(host) - s:send('git-upload-pack '..path..'\0host='..host..'\0') - - local remote = {} - repeat - local ref = s:receive() - if ref then - local sha, name = ref:sub(1,40), ref:sub(42, -2) - remote[name] = sha - end - until not ref - - s:close() - - return remote -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/repo.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/repo.lua deleted file mode 100644 index 07b7207..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/repo.lua +++ /dev/null @@ -1,283 +0,0 @@ -local util = require 'git.util' -local objects = require 'git.objects' -local core = require 'git.core' -local pack = require 'git.pack' - -local join_path = util.join_path -local decompressed = util.decompressed -local read_until_nul = util.read_until_nul -local to_hex = util.to_hex -local object_sha = util.object_sha -local readable_sha = util.readable_sha - -local deflate = core.deflate - -local lfs = require 'lfs' -local assert, error, io, ipairs, print, os, setmetatable, string, table = - assert, error, io, ipairs, print, os, setmetatable, string, table - -module(...) - -Repo = {} -Repo.__index = Repo - --- retrieves an object identified by `sha` from the repository or its packs --- returns a file-like object (supports 'read', 'seek' and 'close'), the size --- of the object and its type --- errors when the object does not exist -function Repo:raw_object(sha) - -- first, look in 'objects' directory - -- first byte of sha is the directory, the rest is name of object file - sha = readable_sha(sha) - local dir = sha:sub(1,2) - local file = sha:sub(3) - local path = join_path(self.dir, 'objects', dir, file) - - if not lfs.attributes(path, 'size') then - -- then, try to look in packs - for _, pack in ipairs(self.packs) do - local obj, len, typ = pack:get_object(sha) - if obj then - return obj, len, typ - end - end - error('Object not found in object neither in packs: '..sha) - else - -- the objects are zlib compressed - local f = decompressed(path) - - -- retrieve the type and length - SP \0 - local content = read_until_nul(f) - local typ, len = content:match('(%w+) (%d+)') - - return f, len, typ - end -end - ---- Store a new object into the repository in `objects` directory. --- @param data A string containing the contents of the new file. --- @param len The length of the data. --- @param type One of 'commit', 'blob', 'tree', 'tag' -function Repo:store_object(data, len, type) - local sha = readable_sha(object_sha(data, len, type)) - local dir = sha:sub(1,2) - local file = sha:sub(3) - util.make_dir(join_path(self.dir, 'objects', dir)) - local path = join_path(self.dir, 'objects', dir, file) - local fo = assert(io.open(path, 'wb')) - local header = type .. ' ' .. len .. '\0' - local compressed = deflate()(header .. data, "finish") - fo:write(compressed) - fo:close() -end - -local function resolvetag(f) - local tag - local line = f:read() - while line do - tag = line:match('^object (%x+)$') - if tag then break end - line = f:read() - end - f:close() - return tag -end - -function Repo:commit(sha) - local f, len, typ = self:raw_object(sha) - while typ == 'tag' do - sha = assert(resolvetag(f), 'could not parse tag for '..readable_sha(sha)) - f, len, typ = self:raw_object(sha) - end - assert(typ == 'commit', string.format('%s (%s) is not a commit', sha, typ)) - - local commit = { id = sha, repo = self, stored = true, parents = {} } - repeat - local line = f:read() - if not line then break end - - local space = line:find(' ') or 0 - local word = line:sub(1, space - 1) - local afterSpace = line:sub(space + 1) - - if word == 'tree' then - commit.tree_sha = afterSpace - elseif word == 'parent' then - table.insert(commit.parents, afterSpace) - elseif word == 'author' then - commit.author = afterSpace - elseif word == 'committer' then - commit.committer = afterSpace - elseif commit.message then - table.insert(commit.message, line) - elseif line == '' then - commit.message = {} - end - until false -- ends with break - f:close() - - commit.message = table.concat(commit.message, '\n') - - return setmetatable(commit, objects.Commit) -end - -function Repo:tree(sha) - local f, len, typ = self:raw_object(sha) - assert(typ == 'tree', string.format('%s (%s) is not a tree', sha, typ)) - - local tree = { id = sha, repo = self, stored = true, _entries = {} } - - while true do - local info = read_until_nul(f) - if not info then break end - local entry_sha = to_hex(f:read(20)) - local mode, name = info:match('^(%d+)%s(.+)$') - local entry_type = 'blob' - if mode == '40000' then - entry_type = 'tree' - elseif mode == '160000' then - entry_type = 'commit' - end - tree._entries[name] = { mode = mode, id = entry_sha, type = entry_type } - end - - f:close() - - return setmetatable(tree, objects.Tree) -end - --- retrieves a Blob -function Repo:blob(sha) - local f, len, typ = self:raw_object(sha) - f:close() -- can be reopened in Blob:content() - - assert(typ == 'blob', string.format('%s (%s) is not a blob', sha, typ)) - return setmetatable({ - id = sha, - len = len, - repo = self, - stored = true }, objects.Blob) -end - -function Repo:head() - return self:commit(self.refs.HEAD) -end - -function Repo:has_object(sha) - local dir = sha:sub(1,2) - local file = sha:sub(3) - local path = join_path(self.dir, 'objects', dir, file) - - if lfs.attributes(path, 'size') then return true end - - for _, pack in ipairs(self.packs) do - local has = pack:has_object(sha) - if has then return true end - end - - return false -end - -function Repo:checkout(sha, target) - if not target then target = self.workDir end - assert(target, 'target directory not specified') - - local commit = self:commit(sha) - commit:checkout(target) - - -- if the repo was checked out using the deepen command (one level of history only) - -- mark the commit's parent as shalow, that is it has no history - if self.isShallow then - -- if it has a parent, mark it shallow - if commit.parents[1] then - local f = assert(io.open(self.dir .. '/shallow', "w")) - f:write(commit.parents[1], '\n') - f:close() - end - end -end - -function Repo:close() - for _, pack in ipairs(self.packs) do - pack:close() - end -end - -function create(dir) - if not dir:match('%.git.?$') then - dir = join_path(dir, '.git') - end - - util.make_dir(dir) - util.make_dir(dir .. '/branches') - util.make_dir(dir .. '/hooks') - util.make_dir(dir .. '/info') - util.make_dir(dir .. '/objects/info') - util.make_dir(dir .. '/objects/pack') - util.make_dir(dir .. '/refs/heads') - util.make_dir(dir .. '/refs/tags') - util.make_dir(dir .. '/refs/remotes') - - do - local f = assert(io.open(dir .. "/HEAD", "w")) - f:write("ref: refs/heads/master\n") - f:close() - end - - local refs = {} - local packs = {} - - return setmetatable({ - dir = dir, - refs = refs, - packs = packs, - }, Repo) -end - --- opens a repository located in working directory `dir` or directly a .git repo -function open(dir) - local workDir = dir - if not dir:match('%.git.?$') then - dir = join_path(dir, '.git') - else - workDir = nil -- no working directory, working directly with repo - end - - local refs = {} - for _,d in ipairs{'refs/heads', 'refs/tags'} do - for fn in lfs.dir(join_path(dir, d)) do - if fn ~= '.' and fn ~= '..' then - local path = join_path(dir, d, fn) - local f = assert(io.open(path), 'rb') - local ref = f:read() - refs[join_path(d, fn)] = ref - f:close() - end - end - end - - local packs = {} - for fn in lfs.dir(join_path(dir, 'objects/pack')) do - if fn:match('%.pack$') then - local path = join_path(dir, 'objects/pack', fn) - table.insert(packs, pack.open(path)) - end - end - - local head = io.open(join_path(dir, 'HEAD'), 'rb') - if head then - local src = head:read() - local HEAD = src:match('ref: (.-)$') - refs.HEAD = refs[HEAD] - head:close() - end - - return setmetatable({ - dir = dir, - workDir = workDir, - refs = refs, - packs = packs, - }, Repo) -end - -return Repo diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/util.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/util.lua deleted file mode 100644 index 4b51c80..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/git/util.lua +++ /dev/null @@ -1,233 +0,0 @@ -local lfs = require 'lfs' -local core = require 'git.core' -local deflate = core.deflate -local inflate = core.inflate -local sha = core.sha - -module(..., package.seeall) - -local BUF_SIZE = 4096 - -local dirsep = package.config:sub(1,1) - --- replaces '/' path separators on Windows with the correct ones ('\\') -function correct_separators(path) - return path:gsub('/', dirsep) -end - --- joins several path components into a single path, uses system-specific directory --- separator, cleans input, i.e. join_path('a/', 'b', 'c/') => 'a/b/c' -function join_path(...) - local n = select('#', ...) - local args = {...} - for i=1,n do - args[i] = args[i]:gsub(dirsep..'?$', '') - end - return table.concat(args, dirsep, 1, n) -end - --- Return the path with the all occurences of '/.' or '\.' (representing --- the current directory) removed. -local function remove_curr_dir_dots(path) - while path:match(dirsep .. "%." .. dirsep) do -- match("/%./") - path = path:gsub(dirsep .. "%." .. dirsep, dirsep) -- gsub("/%./", "/") - end - return path:gsub(dirsep .. "%.$", "") -- gsub("/%.$", "") -end - --- Return whether the path is a root. -local function is_root(path) - return path:find("^[%u%U.]?:?[/\\]$") -end - --- Return the path with the unnecessary trailing separator removed. -local function remove_trailing(path) - if path:sub(-1) == dirsep and not is_root(path) then path = path:sub(1,-2) end - return path -end - --- Extract file or directory name from its path. -local function extract_name(path) - if is_root(path) then return path end - - path = remove_trailing(path) - path = path:gsub("^.*" .. dirsep, "") - return path -end - --- Return the string 'str', with all magic (pattern) characters escaped. -local function escape_magic(str) - local escaped = str:gsub('[%-%.%+%[%]%(%)%^%%%?%*%^%$]','%%%1') - return escaped -end - --- Return parent directory of the 'path' or nil if there's no parent directory. --- If 'path' is a path to file, return the directory the file is in. -function parent_dir(path) - path = remove_curr_dir_dots(path) - path = remove_trailing(path) - - local dir = path:gsub(escape_magic(extract_name(path)) .. "$", "") - if dir == "" then - return nil - else - return remove_trailing(dir) - end -end - --- Make a new directory, making also all of its parent directories that doesn't exist. -function make_dir(path) - if lfs.attributes(path) then - return true - else - local par_dir = parent_dir(path) - if par_dir then - assert(make_dir(par_dir)) - end - return lfs.mkdir(path) - end -end - - --- Reader class --- adapted from Penlight: https://raw.github.com/stevedonovan/Penlight/master/lua/pl/stringio.lua - -local SR = {} -SR.__index = SR - -function SR:_read(fmt) - local i,str = self.i,self.str - local sz = #str - if i > sz then return nil, "past end of file" end - local res - if fmt == '*l' or fmt == '*L' then - local idx = str:find('\n',i) or (sz+1) - res = str:sub(i,fmt == '*l' and idx-1 or idx) - self.i = idx+1 - elseif fmt == '*a' then - res = str:sub(i) - self.i = sz+1 - elseif fmt == '*n' then - local _,i2,i2,idx - _,idx = str:find ('%s*%d+',i) - _,i2 = str:find ('^%.%d+',idx+1) - if i2 then idx = i2 end - _,i2 = str:find ('^[eE][%+%-]*%d+',idx+1) - if i2 then idx = i2 end - local val = str:sub(i,idx) - res = tonumber(val) - self.i = idx+1 - elseif type(fmt) == 'number' then - res = str:sub(i,i+fmt-1) - self.i = i + fmt - else - error("bad read format",2) - end - return res - end - -function SR:read(...) - if select('#',...) == 0 then - return self:_read('*l') - else - local res, fmts = {},{...} - for i = 1, #fmts do - res[i] = self:_read(fmts[i]) - end - return unpack(res) - end - end - -function SR:seek(whence,offset) - local base - whence = whence or 'cur' - offset = offset or 0 - if whence == 'set' then - base = 1 - elseif whence == 'cur' then - base = self.i - elseif whence == 'end' then - base = #self.str - end - self.i = base + offset - return self.i -end - -function SR:close() -- for compatibility only -end - ---- create a file-like object for reading from a given string. --- @param s The input string. -function reader(s) - return setmetatable({str=s,i=1},SR) -end - - --- decompress the file and return a handle to temporary uncompressed file -function decompressed(path) - local fi = assert(io.open(path, 'rb')) - local result = {} - - local z = inflate() - repeat - local str = fi:read(BUF_SIZE) - local data = z(str) - if type(data) == 'string' then - result[#result+1] = data - else print('!!!', data) end - until not str - fi:close() - - return reader(table.concat(result)) -end - --- reads until the byte \0, consumes it and returns the string up to the \0 -function read_until_nul(f) - local t = {} - repeat - local c = f:read(1) - if c and c ~= '\0' then t[#t+1] = c end - until not c or c == '\0' - if #t > 0 then - return table.concat(t) - else - return nil - end -end - --- converts a string to lowercase hex -function to_hex(s) - return (s:gsub('.', function(c) - return string.format('%02x', string.byte(c)) - end)) -end - --- converts a string from hex to binary -function from_hex(s) - return (s:gsub('..', function(cc) - return string.char(tonumber(cc, 16)) - end)) -end - --- always returns readable (hex) hash -function readable_sha(s) - if #s ~= 40 then return to_hex(s) - else return s end -end - --- always returns binary hash -function binary_sha(s) - if #s ~= 20 then return from_hex(s) - else return s end -end - -function object_sha(data, len, type) - local header = type .. ' ' .. len .. '\0' - local res = sha(header .. data) - return res -end - -function deflate(data) - local c = deflate() - return c(data, "finish") -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ltn12.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ltn12.lua deleted file mode 100644 index 5b10f56..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ltn12.lua +++ /dev/null @@ -1,298 +0,0 @@ ------------------------------------------------------------------------------ --- LTN12 - Filters, sources, sinks and pumps. --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local table = require("table") -local base = _G -local _M = {} -if module then -- heuristic for exporting a global package table - ltn12 = _M -end -local filter,source,sink,pump = {},{},{},{} - -_M.filter = filter -_M.source = source -_M.sink = sink -_M.pump = pump - --- 2048 seems to be better in windows... -_M.BLOCKSIZE = 2048 -_M._VERSION = "LTN12 1.0.3" - ------------------------------------------------------------------------------ --- Filter stuff ------------------------------------------------------------------------------ --- returns a high level filter that cycles a low-level filter -function filter.cycle(low, ctx, extra) - base.assert(low) - return function(chunk) - local ret - ret, ctx = low(ctx, chunk, extra) - return ret - end -end - --- chains a bunch of filters together --- (thanks to Wim Couwenberg) -function filter.chain(...) - local arg = {...} - local n = select('#',...) - local top, index = 1, 1 - local retry = "" - return function(chunk) - retry = chunk and retry - while true do - if index == top then - chunk = arg[index](chunk) - if chunk == "" or top == n then return chunk - elseif chunk then index = index + 1 - else - top = top+1 - index = top - end - else - chunk = arg[index](chunk or "") - if chunk == "" then - index = index - 1 - chunk = retry - elseif chunk then - if index == n then return chunk - else index = index + 1 end - else base.error("filter returned inappropriate nil") end - end - end - end -end - ------------------------------------------------------------------------------ --- Source stuff ------------------------------------------------------------------------------ --- create an empty source -local function empty() - return nil -end - -function source.empty() - return empty -end - --- returns a source that just outputs an error -function source.error(err) - return function() - return nil, err - end -end - --- creates a file source -function source.file(handle, io_err) - if handle then - return function() - local chunk = handle:read(_M.BLOCKSIZE) - if not chunk then handle:close() end - return chunk - end - else return source.error(io_err or "unable to open file") end -end - --- turns a fancy source into a simple source -function source.simplify(src) - base.assert(src) - return function() - local chunk, err_or_new = src() - src = err_or_new or src - if not chunk then return nil, err_or_new - else return chunk end - end -end - --- creates string source -function source.string(s) - if s then - local i = 1 - return function() - local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1) - i = i + _M.BLOCKSIZE - if chunk ~= "" then return chunk - else return nil end - end - else return source.empty() end -end - --- creates rewindable source -function source.rewind(src) - base.assert(src) - local t = {} - return function(chunk) - if not chunk then - chunk = table.remove(t) - if not chunk then return src() - else return chunk end - else - table.insert(t, chunk) - end - end -end - -function source.chain(src, f) - base.assert(src and f) - local last_in, last_out = "", "" - local state = "feeding" - local err - return function() - if not last_out then - base.error('source is empty!', 2) - end - while true do - if state == "feeding" then - last_in, err = src() - if err then return nil, err end - last_out = f(last_in) - if not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - elseif last_out ~= "" then - state = "eating" - if last_in then last_in = "" end - return last_out - end - else - last_out = f(last_in) - if last_out == "" then - if last_in == "" then - state = "feeding" - else - base.error('filter returned ""') - end - elseif not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - else - return last_out - end - end - end - end -end - --- creates a source that produces contents of several sources, one after the --- other, as if they were concatenated --- (thanks to Wim Couwenberg) -function source.cat(...) - local arg = {...} - local src = table.remove(arg, 1) - return function() - while src do - local chunk, err = src() - if chunk then return chunk end - if err then return nil, err end - src = table.remove(arg, 1) - end - end -end - ------------------------------------------------------------------------------ --- Sink stuff ------------------------------------------------------------------------------ --- creates a sink that stores into a table -function sink.table(t) - t = t or {} - local f = function(chunk, err) - if chunk then table.insert(t, chunk) end - return 1 - end - return f, t -end - --- turns a fancy sink into a simple sink -function sink.simplify(snk) - base.assert(snk) - return function(chunk, err) - local ret, err_or_new = snk(chunk, err) - if not ret then return nil, err_or_new end - snk = err_or_new or snk - return 1 - end -end - --- creates a file sink -function sink.file(handle, io_err) - if handle then - return function(chunk, err) - if not chunk then - handle:close() - return 1 - else return handle:write(chunk) end - end - else return sink.error(io_err or "unable to open file") end -end - --- creates a sink that discards data -local function null() - return 1 -end - -function sink.null() - return null -end - --- creates a sink that just returns an error -function sink.error(err) - return function() - return nil, err - end -end - --- chains a sink with a filter -function sink.chain(f, snk) - base.assert(f and snk) - return function(chunk, err) - if chunk ~= "" then - local filtered = f(chunk) - local done = chunk and "" - while true do - local ret, snkerr = snk(filtered, err) - if not ret then return nil, snkerr end - if filtered == done then return 1 end - filtered = f(done) - end - else return 1 end - end -end - ------------------------------------------------------------------------------ --- Pump stuff ------------------------------------------------------------------------------ --- pumps one chunk from the source to the sink -function pump.step(src, snk) - local chunk, src_err = src() - local ret, snk_err = snk(chunk, src_err) - if chunk and ret then return 1 - else return nil, src_err or snk_err end -end - --- pumps all data from a source to a sink, using a step function -function pump.all(src, snk, step) - base.assert(src and snk) - step = step or pump.step - while true do - local ret, err = step(src, snk) - if not ret then - if err then return nil, err - else return 1 end - end - end -end - -return _M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_lexer_loose.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_lexer_loose.lua deleted file mode 100644 index 678a693..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_lexer_loose.lua +++ /dev/null @@ -1,212 +0,0 @@ ---[[ - lua_lexer_loose.lua. - Loose lexing of Lua code. See README. - - WARNING: This code is preliminary and may have errors - in its current form. - - (c) 2013 David Manura. MIT License. ---]] - -local M = {} - --- based on LuaBalanced -local function match_string(s, pos) - pos = pos or 1 - local posa = pos - local c = s:sub(pos,pos) - if c == '"' or c == "'" then - pos = pos + 1 - while 1 do - pos = s:find("[" .. c .. "\\]", pos) - if not pos then return s:sub(posa), #s + 1 end -- not terminated string - if s:sub(pos,pos) == c then - local part = s:sub(posa, pos) - return part, pos + 1 - else - pos = pos + 2 - end - end - else - local sc = s:match("^%[(=*)%[", pos) - if sc then - local _; _, pos = s:find("%]" .. sc .. "%]", pos) - if not pos then return s:sub(posa), #s + 1 end -- not terminated string - local part = s:sub(posa, pos) - return part, pos + 1 - else - return nil, pos - end - end -end - --- based on LuaBalanced -local function match_comment(s, pos) - pos = pos or 1 - if s:sub(pos, pos+1) ~= '--' then - return nil, pos - end - pos = pos + 2 - if s:sub(pos,pos) == '[' then - local partt, post = match_string(s, pos) - if partt then - return '--' .. partt, post - end - end - local part; part, pos = s:match('^([^\n]*\n?)()', pos) - return '--' .. part, pos -end - --- note: matches invalid numbers too (for example, 0x) -local function match_numberlike(s, pos) - local hex = s:match('^0[xX]', pos) - if hex then pos = pos + #hex end - - local longint = (hex and '^%x+' or '^%d+') .. '[uU]?[lL][lL]' - local mantissa1 = hex and '^%x+%.?%x*' or '^%d+%.?%d*' - local mantissa2 = hex and '^%.%x+' or '^%.%d+' - local exponent = hex and '^[pP][+%-]?%x*' or '^[eE][+%-]?%d*' - local imaginary = '^[iI]' - local tok = s:match(longint, pos) - if not tok then - tok = s:match(mantissa1, pos) or s:match(mantissa2, pos) - if tok then - local tok2 = s:match(exponent, pos + #tok) - if tok2 then tok = tok..tok2 end - tok2 = s:match(imaginary, pos + #tok) - if tok2 then tok = tok..tok2 end - end - end - return tok and (hex or '') .. tok or hex -end - -local function newset(s) - local t = {} - for c in s:gmatch'.' do t[c] = true end - return t -end -local function qws(s) - local t = {} - for k in s:gmatch'%S+' do t[k] = true end - return t -end - -local sym = newset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_") -local dig = newset('0123456789') -local name = "([_A-Za-z][_A-Za-z0-9]*)" -local op = newset('=~<>.+-*/%^#=<>;:,.{}[]()') - -op['=='] = true -op['<='] = true -op['>='] = true -op['~='] = true -op['..'] = true -op['<<'] = true -op['>>'] = true -op['//'] = true - -local is_keyword = qws[[ - and break do else elseif end false for function if - in local nil not or repeat return - then true until while goto]] - -function M.lex(code, f, pos) - local pos = pos or 1 - local tok = code:match('^#![^\n]*\n', pos) -- shebang - if tok then f('Shebang', tok, 1) pos = pos + #tok end - while pos <= #code do - local p2, n2, n1, n3 = code:match('^%s*()((%S)(%S?))', pos) - if not p2 then assert(code:sub(pos):match('^%s*$')); break end - pos = p2 - - if sym[n1] then - local tok = code:match('^'..name, pos) - assert(tok) - if is_keyword[tok] then - f('Keyword', tok, pos) - else - f('Id', tok, pos) - end - pos = pos + #tok - elseif n2 == '--' then - local tok, pos2 = match_comment(code, pos) - assert(tok) - f('Comment', tok, pos) - pos = pos2 - elseif n2 == '::' then - local tok = code:match('^(::%s*'..name..'%s*::)', pos) - if tok then - f('Label', tok, pos) - pos = pos + #tok - else - f('Unknown', code:sub(pos, pos+1), pos) -- unterminated label - pos = pos + 2 - end - elseif n1 == '\'' or n1 == '\"' or n2 == '[[' or n2 == '[=' then - local tok = match_string(code, pos) - if tok then - f('String', tok, pos) - pos = pos + #tok - else - f('Unknown', code:sub(pos), pos) -- unterminated string - pos = #code + 1 - end - elseif dig[n1] or (n1 == '.' and dig[n3]) then - local tok = match_numberlike(code, pos) - assert(tok) - f('Number', tok, pos) - pos = pos + #tok - elseif op[n2] then - if n2 == '..' and code:match('^%.', pos+2) then - tok = '...' - else - tok = n2 - end - f('Keyword', tok, pos) - pos = pos + #tok - elseif op[n1] then - local tok = n1 - f('Keyword', tok, pos) - pos = pos + #tok - else - f('Unknown', n1, pos) - pos = pos + 1 - end - end -end - -local Stream = {} -Stream.__index = Stream -function Stream:next(val) - if self._next then - local _next = self._next - self._next = nil - return _next - else - self._next = nil - return self.f() - end -end -function Stream:peek() - if self._next then - return self._next - else - local _next = self.f() - self._next = _next - return _next - end -end - -function M.lexc(code, f, pos) - local yield = coroutine.yield - local func = coroutine.wrap(f or function() - M.lex(code, function(tag, name, pos) - -- skip Comment tags as they may arbitrarily split statements and affects their processing - if tag ~= 'Comment' then yield {tag=tag, name, lineinfo=pos} end - end, pos) - yield {tag='Eof', lineinfo = #code+1} - end) - return setmetatable({f=func}, Stream) -end - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_parser_loose.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_parser_loose.lua deleted file mode 100644 index e64493f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/lua_parser_loose.lua +++ /dev/null @@ -1,337 +0,0 @@ ---[[ - lua_parser_loose.lua. - Loose parsing of Lua code. See README. - (c) 2013 David Manura. MIT License. ---]] - -local PARSE = {} - -local unpack = table.unpack or unpack -local LEX = require 'lua_lexer_loose' - ---[[ - Loose parser. - - lx - lexer stream of Lua tokens. - f(event...) - callback function to send events to. - - Events generated: - 'Var', name, lineinfo - variable declaration that immediately comes into scope. - 'VarSelf', name, lineinfo - same as 'Var' but for implicit 'self' parameter - in method definitions. lineinfo is zero-width space after '(' - 'VarNext', name, lineinfo - variable definition that comes into scope - upon next statement. - 'VarInside', name, lineinfo - variable definition that comes into scope - inside following block. Used for control variables in 'for' statements. - 'Id', name, lineinfo - reference to variable. - 'String', name - string or table field. - 'Scope', opt - beginning of scope block. - 'EndScope', nil, lineinfo - end of scope block. - 'FunctionCall', name, lineinfo - function call (in addition to other events). - 'Function', name, lineinfo - function definition. ---]] -function PARSE.parse_scope(lx, f, level) - local cprev = {tag='Eof'} - - -- stack of scopes. - local scopes = {{}} - for l = 2, (level or 1) do scopes[l] = {} end - - local function scope_begin(opt, lineinfo, nobreak) - scopes[#scopes+1] = {} - f('Scope', opt, lineinfo, nobreak) - end - local function scope_end(opt, lineinfo) - local scope = #scopes - if scope > 1 then table.remove(scopes) end - local inside_local = false - for scope = scope-1, 1, -1 do - if scopes[scope].inside_local then inside_local = true; break end - end - f('EndScope', opt, lineinfo, inside_local) - end - - local function parse_function_list(has_self, name, pos) - local c = lx:next(); assert(c[1] == '(') - f('Statement', c[1], c.lineinfo, true) -- generate Statement for function definition - scope_begin(c[1], c.lineinfo, true) - - local vars = {} -- accumulate vars (if any) to send after 'Function' - if has_self then - local lineinfo = c.lineinfo+1 -- zero size - table.insert(vars, {'VarSelf', 'self', lineinfo, true}) - end - while true do - local n = lx:peek() - if not (n.tag == 'Id' or n.tag == 'Keyword' and n[1] == '...') then break end - local c = lx:next() - if c.tag == 'Id' then table.insert(vars, {'Var', c[1], c.lineinfo, true}) end - -- ignore '...' in this case - if lx:peek()[1] == ',' then lx:next() end - end - if lx:peek()[1] == ')' then - lx:next() - f('Function', name, pos or c.lineinfo, true) - end - for _, var in ipairs(vars) do f(unpack(var)) end - end - - while true do - local c = lx:next() - - -- Detect end of previous statement - if c.tag == 'Eof' -- trigger 'Statement' at the end of file - or c.tag == 'Keyword' and ( - c[1] == 'break' or c[1] == 'goto' or c[1] == 'do' or c[1] == 'while' or - c[1] == 'repeat' or c[1] == 'if' or c[1] == 'for' or c[1] == 'function' and lx:peek().tag == 'Id' or - c[1] == 'local' or c[1] == ';' or c[1] == 'until' or c[1] == 'return' or c[1] == 'end') or - c.tag == 'Id' and - (cprev.tag == 'Id' or - cprev.tag == 'Keyword' and - (cprev[1] == ']' or cprev[1] == ')' or cprev[1] == '}' or - cprev[1] == '...' or cprev[1] == 'end' or - cprev[1] == 'true' or cprev[1] == 'false' or - cprev[1] == 'nil') or - cprev.tag == 'Number' or cprev.tag == 'String') - then - if scopes[#scopes].inside_until then scope_end(nil, c.lineinfo) end - local scope = #scopes - if not scopes[scope].inside_table then scopes[scope].inside_local = nil end - f('Statement', c[1], c.lineinfo, - scopes[scope].inside_local or c[1] == 'local' or c[1] == 'function' or c[1] == 'end') - end - - if c.tag == 'Eof' then break end - - -- Process token(s) - if c.tag == 'Keyword' then - - if c[1] == 'local' and lx:peek().tag == 'Keyword' and lx:peek()[1] == 'function' then - -- local function - local c = lx:next(); assert(c[1] == 'function') - if lx:peek().tag == 'Id' then - c = lx:next() - f('Var', c[1], c.lineinfo, true) - if lx:peek()[1] == '(' then parse_function_list(nil, c[1], c.lineinfo) end - end - elseif c[1] == 'function' then - if lx:peek()[1] == '(' then -- inline function - parse_function_list() - elseif lx:peek().tag == 'Id' then -- function definition statement - c = lx:next(); assert(c.tag == 'Id') - local name = c[1] - local pos = c.lineinfo - f('Id', name, pos, true) - local has_self - while lx:peek()[1] ~= '(' and lx:peek().tag ~= 'Eof' do - c = lx:next() - name = name .. c[1] - if c.tag == 'Id' then - f('String', c[1], c.lineinfo, true) - elseif c.tag == 'Keyword' and c[1] == ':' then - has_self = true - end - end - if lx:peek()[1] == '(' then parse_function_list(has_self, name, pos) end - end - elseif c[1] == 'local' and lx:peek().tag == 'Id' then - scopes[#scopes].inside_local = true - c = lx:next() - f('VarNext', c[1], c.lineinfo, true) - while lx:peek().tag == 'Keyword' and lx:peek()[1] == ',' do - c = lx:next(); if lx:peek().tag ~= 'Id' then break end - c = lx:next() - f('VarNext', c[1], c.lineinfo, true) - end - elseif c[1] == 'for' and lx:peek().tag == 'Id' then - c = lx:next() - f('VarInside', c[1], c.lineinfo, true) - while lx:peek().tag == 'Keyword' and lx:peek()[1] == ',' do - c = lx:next(); if lx:peek().tag ~= 'Id' then break end - c = lx:next() - f('VarInside', c[1], c.lineinfo, true) - end - elseif c[1] == 'goto' and lx:peek().tag == 'Id' then - lx:next() - elseif c[1] == 'do' then - scope_begin('do', c.lineinfo) - -- note: do/while/for statement scopes all begin at 'do'. - elseif c[1] == 'repeat' or c[1] == 'then' then - scope_begin(c[1], c.lineinfo) - elseif c[1] == 'end' or c[1] == 'elseif' then - scope_end(c[1], c.lineinfo) - elseif c[1] == 'else' then - scope_end(nil, c.lineinfo) - scope_begin(c[1], c.lineinfo) - elseif c[1] == 'until' then - scopes[#scopes].inside_until = true - elseif c[1] == '{' then - scopes[#scopes].inside_table = (scopes[#scopes].inside_table or 0) + 1 - elseif c[1] == '}' then - local newval = (scopes[#scopes].inside_table or 0) - 1 - newval = newval >= 1 and newval or nil - scopes[#scopes].inside_table = newval - end - elseif c.tag == 'Id' then - local scope = #scopes - local inside_local = scopes[scope].inside_local ~= nil - local inside_table = scopes[scope].inside_table - local cnext = lx:peek() - if cnext.tag == 'Keyword' and (cnext[1] == '(' or cnext[1] == '{') - or cnext.tag == 'String' then - f('FunctionCall', c[1], c.lineinfo, inside_local) - end - -- either this is inside a table or it continues from a comma, - -- which may be a field assignment, so assume it's in a table - if (inside_table or cprev[1] == ',') and cnext.tag == 'Keyword' and cnext[1] == '=' then - -- table field; table fields are tricky to handle during incremental - -- processing as "a = 1" may be either an assignment (in which case - -- 'a' is Id) or a field initialization (in which case it's a String). - -- Since it's not possible to decide between two cases in isolation, - -- this is not a good place to insert a break; instead, the break is - -- inserted at the location of the previous keyword, which allows - -- to properly handle those cases. The desired location of - -- the restart point is returned as the `nobreak` value. - f('String', c[1], c.lineinfo, - inside_local or cprev and cprev.tag == 'Keyword' and cprev.lineinfo) - elseif cprev.tag == 'Keyword' and (cprev[1] == ':' or cprev[1] == '.') then - f('String', c[1], c.lineinfo, true) - else - f('Id', c[1], c.lineinfo, true) - -- this looks like the left side of (multi-variable) assignment - -- unless it's a part of `= var, field = value`, so skip if inside a table - if not inside_table and not (cprev and cprev.tag == 'Keyword' and cprev[1] == '=') then - while lx:peek().tag == 'Keyword' and lx:peek()[1] == ',' do - local c = lx:next(); if lx:peek().tag ~= 'Id' then break end - c = lx:next() - f('Id', c[1], c.lineinfo, true) - end - end - end - end - - if c.tag ~= 'Comment' then cprev = c end - end -end - ---[[ - This is similar to parse_scope but determines if variables are local or global. - - lx - lexer stream of Lua tokens. - f(event...) - callback function to send events to. - - Events generated: - 'Id', name, lineinfo, 'local'|'global' - (plus all events in parse_scope) ---]] -function PARSE.parse_scope_resolve(lx, f, vars) - local NEXT = {} -- unique key - local INSIDE = {} -- unique key - local function newscope(vars, opt, lineinfo) - local newvars = opt=='do' and vars[INSIDE] or {} - if newvars == vars[INSIDE] then vars[INSIDE] = false end - newvars[INSIDE]=false - newvars[NEXT]=false - local level = (vars[0] or 0) + 1 - newvars[0] = level -- keep the current level - newvars[-1] = lineinfo -- keep the start of the scope - newvars[level] = newvars -- reference the current vars table - return setmetatable(newvars, {__index=vars}) - end - - vars = vars or newscope({[0] = 0}, nil, 1) - vars[NEXT] = false -- vars that come into scope upon next statement - vars[INSIDE] = false -- vars that come into scope upon entering block - PARSE.parse_scope(lx, function(op, name, lineinfo, nobreak) - -- in some (rare) cases VarNext can follow Statement event (which copies - -- vars[NEXT]). This may cause vars[0] to be `nil`, so default to 1. - local var = op:find("^Var") and - {fpos = lineinfo, at = (vars[0] or 1) + (op == 'VarInside' and 1 or 0), - masked = vars[name], self = (op == 'VarSelf') or nil } or nil - if op == 'Var' or op == 'VarSelf' then - vars[name] = var - elseif op == 'VarNext' then - vars[NEXT] = vars[NEXT] or {} - vars[NEXT][name] = var - elseif op == 'VarInside' then - vars[INSIDE] = vars[INSIDE] or {} - vars[INSIDE][name] = var - elseif op == 'Scope' then - vars = newscope(vars, name, lineinfo) - elseif op == 'EndScope' then - local mt = getmetatable(vars) - if mt ~= nil then vars = mt.__index end - elseif op == 'Id' - or op == 'String' or op == 'FunctionCall' or op == 'Function' then - -- Just make callback - elseif op == 'Statement' then -- beginning of statement - -- Apply vars that come into scope upon beginning of statement. - if vars[NEXT] then - for k,v in pairs(vars[NEXT]) do - vars[k] = v; vars[NEXT][k] = nil - end - end - else - assert(false) - end - f(op, name, lineinfo, vars, nobreak) - end, vars[0]) -end - -function PARSE.extract_vars(code, f) - local lx = LEX.lexc(code) - - local char0 = 1 -- next char offset to write - local function gen(char1, nextchar0) - char0 = nextchar0 - end - - PARSE.parse_scope_resolve(lx, function(op, name, lineinfo, other) - if op == 'Id' then - f('Id', name, other, lineinfo) - elseif op == 'Var' or op == 'VarNext' or op == 'VarInside' then - gen(lineinfo, lineinfo+#name) - f('Var', name, "local", lineinfo) - end -- ignore 'VarSelf' and others - end) - gen(#code+1, nil) -end - ---[[ - Converts 5.2 code to 5.1 style code with explicit _ENV variables. - Example: "function f(_ENV, x) print(x, y)" --> - "function _ENV.f(_ENV, x) _ENV.print(x, _ENV.y) end" - - code - string of Lua code. Assumed to be valid Lua (FIX: 5.1 or 5.2?) - f(s) - call back function to send chunks of Lua code output to. Example: io.stdout. ---]] -function PARSE.replace_env(code, f) - if not f then return PARSE.accumulate(PARSE.replace_env, code) end - PARSE.extract_vars(code, function(op, name, other) - if op == 'Id' then - f(other == 'global' and '_ENV.' .. name or name) - elseif op == 'Var' or op == 'Other' then - f(name) - end - end) -end - --- helper function. Can be passed as argument `f` to functions --- like `replace_env` above to accumulate fragments into a single string. -function PARSE.accumulator() - local ts = {} - local mt = {} - mt.__index = mt - function mt:__call(s) ts[#ts+1] = s end - function mt:result() return table.concat(ts) end - return setmetatable({}, mt) -end - --- helper function -function PARSE.accumulate(g, code) - local accum = PARSE.accumulator() - g(code, accum) - return accum:result() -end - -return PARSE diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luadist.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luadist.lua deleted file mode 100644 index da875dc..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luadist.lua +++ /dev/null @@ -1,746 +0,0 @@ -#!/usr/bin/env lua - --- Command line interface to LuaDist-git. - -local dist = require "dist" -local utils = require "dist.utils" -local depends = require "dist.depends" -local package = require "dist.package" -local mf = require "dist.manifest" -local cfg = require "dist.config" -local sys = require "dist.sys" - --- CLI commands of Luadist. -local commands -commands = { - - -- Print help for this command line interface. - ["help"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] [ARGUMENTS...] [-VARIABLES...] - - Commands: - - help - print this help - install - install modules - remove - remove modules - refresh - update information about modules in repositories - list - list installed modules - info - show information about modules - search - search repositories for modules - fetch - download modules - make - manually deploy modules from local paths - upload - upload installed modules to their repositories - tree - print dependency tree of a module - selftest - run the selftest of LuaDist - - To get help on specific command, run: - - luadist help - ]], - run = function (deploy_dir, help_item) - deploy_dir = deploy_dir or dist.get_deploy_dir() - help_item = help_item or {} - assert(type(deploy_dir) == "string", "luadist.help: Argument 'deploy_dir' is not a string.") - assert(type(help_item) == "table", "luadist.help: Argument 'help_item' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - if not help_item or not commands[help_item[1]] then - help_item = "help" - else - help_item = help_item[1] - end - - print_info() - print(commands[help_item].help) - return 0 - end - }, - - -- Install modules. - ["install"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] install MODULES... [-VARIABLES...] - - The 'install' command will install specified MODULES to - DEPLOYMENT_DIRECTORY. LuaDist will also automatically resolve, download - and install all dependencies. - - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. - - You can use * (an asterisk sign) in the name of the module as a wildcard - with the meaning 'any symbols' (in most shells, the module name then must - be quoted to prevent the expansion of asterisk by the shell itself). - - Optional CMake VARIABLES in -D format (e.g. -Dvariable=value) or LuaDist - configuration VARIABLES (e.g. -variable=value) can be specified. - - The -simulate configuration option makes LuaDist only to simulate the - installation of modules (no modules will be really installed). - ]], - - run = function (deploy_dir, modules, cmake_variables) - deploy_dir = deploy_dir or dist.get_deploy_dir() - if type(modules) == "string" then modules = {modules} end - cmake_variables = cmake_variables or {} - assert(type(deploy_dir) == "string", "luadist.install: Argument 'deploy_dir' is not a string.") - assert(type(modules) == "table", "luadist.install: Argument 'modules' is not a string or table.") - assert(type(cmake_variables) == "table", "luadist.install: Argument 'cmake_variables' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - if cfg.simulate then - print("NOTE: this is just simulation.") - end - - if #modules == 0 then - print("No modules to install specified.") - return 0 - end - - local ok, err = dist.install(modules, deploy_dir, cmake_variables) - if not ok then - print(err) - os.exit(1) - else - print((cfg.simulate and "Simulated installation" or "Installation") .. " successful.") - return 0 - end - end - }, - - -- Remove modules. - ["remove"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] remove MODULES... [-VARIABLES...] - - The 'remove' command will remove specified MODULES from - DEPLOYMENT_DIRECTORY. If no module is specified, all modules - will be removed. - - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. If no MODULES are specified, all installed modules - will be removed. - - You can use * (an asterisk sign) in the name of the module as a wildcard - with the meaning 'any symbols' (in most shells, the module name then must - be quoted to prevent the expansion of asterisk by the shell itself). - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - - WARNING: dependencies between modules are NOT taken into account when - removing modules! - ]], - - run = function (deploy_dir, modules) - deploy_dir = deploy_dir or dist.get_deploy_dir() - if type(modules) == "string" then modules = {modules} end - assert(type(deploy_dir) == "string", "luadist.remove: Argument 'deploy_dir' is not a string.") - assert(type(modules) == "table", "luadist.remove: Argument 'modules' is not a string or table.") - deploy_dir = sys.abs_path(deploy_dir) - - local num, err = dist.remove(modules, deploy_dir) - if not num then - print(err) - os.exit(1) - else - print("Removed modules: " .. num) - return 0 - end - end - }, - - -- Update repositories. - ["refresh"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] refresh [-VARIABLES...] - - The 'refresh' command will update information about modules in all software - repositories of specified DEPLOYMENT_DIRECTORY. Also, the cached dependency - manifest, built from previous installations or invocations of 'tree' - functionality will be deleted. - - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir) - deploy_dir = deploy_dir or dist.get_deploy_dir() - assert(type(deploy_dir) == "string", "luadist.refresh: Argument 'deploy_dir' is not a string.") - deploy_dir = sys.abs_path(deploy_dir) - - -- TODO: should be deleting the dep_manifest decoupled from refreshing the repository info? - -- delete cached dependency manifest - local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file)) - local dep_mf_deleted = false - if sys.exists(dep_manifest_file) then - sys.delete(dep_manifest_file) - dep_mf_deleted = true - end - - -- refresh repository information - local ok, err = dist.update_manifest(deploy_dir) - if not ok then - print(err) - os.exit(1) - else - print("Repositories successfuly updated" .. (dep_mf_deleted and " and dependency cache deleted" or "") .. ".") - return 0 - end - end - }, - - -- Manually deploy modules. - ["make"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] make MODULE_PATHS... [-VARIABLES...] - - The 'make' command will manually deploy modules from specified local - MODULE_PATHS into the DEPLOYMENT_DIRECTORY. - - The MODULE_PATHS will be preserved. If DEPLOYMENT_DIRECTORY is not - specified, the deployment directory of LuaDist is used. - - Optional CMake VARIABLES in -D format (e.g. -Dvariable=value) or LuaDist - configuration VARIABLES (e.g. -variable=value) can be specified. - - The -simulate configuration option makes LuaDist only to simulate the - deployment of modules (no modules will be really deployed). - - WARNING: this command does NOT check whether the dependencies of deployed - modules are satisfied or not! - ]], - - run = function (deploy_dir, module_paths, cmake_variables) - deploy_dir = deploy_dir or dist.get_deploy_dir() - module_paths = module_paths or {} - cmake_variables = cmake_variables or {} - assert(type(deploy_dir) == "string", "luadist.make: Argument 'deploy_dir' is not a string.") - assert(type(module_paths) == "table", "luadist.make: Argument 'module_paths' is not a table.") - assert(type(cmake_variables) == "table", "luadist.make: Argument 'cmake_variables' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - if cfg.simulate then - print("NOTE: this is just simulation.") - end - - if #module_paths == 0 then - print("No module paths to deploy specified.") - return 0 - end - - local ok, err = dist.make(deploy_dir, module_paths, cmake_variables) - if not ok then - print(err) - os.exit(1) - end - print((cfg.simulate and "Simulated deployment" or "Deployment") .. " successful.") - return 0 - end - }, - - -- Download modules. - ["fetch"] = { - help = [[ -Usage: luadist [FETCH_DIRECTORY] fetch MODULES... [-VARIABLES...] - - The 'fetch' command will download specified MODULES to the FETCH_DIRECTORY. - - If no FETCH_DIRECTORY is specified, the temporary directory of LuaDist - deployment directory (i.e. ']] .. cfg.temp_dir .. [[') is used. - If the version is not specified in module name, the most recent version - available will be downloaded. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (fetch_dir, modules) - fetch_dir = fetch_dir or dist.get_deploy_dir() - modules = modules or {} - assert(type(fetch_dir) == "string", "luadist.fetch: Argument 'fetch_dir' is not a string.") - assert(type(modules) == "table", "luadist.fetch: Argument 'modules' is not a table.") - fetch_dir = sys.abs_path(fetch_dir) - - -- if the default parameter (i.e. deploy_dir) is passed, use the default temp_dir - if fetch_dir == dist.get_deploy_dir() then - fetch_dir = sys.make_path(fetch_dir, cfg.temp_dir) - end - - if #modules == 0 then - print("No modules to download specified.") - return 0 - end - - local ok, err = dist.fetch(modules, fetch_dir) - if not ok then - print(err) - os.exit(1) - else - print("Modules successfuly downloaded to '" .. fetch_dir .. "'.") - return 0 - end - end - }, - - -- Upload modules. - ["upload"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] upload MODULES... [-VARIABLES...] - - The 'upload' command will upload the binary versions of specified MODULES, - installed in the DEPLOYMENT_DIRECTORY, to their LuaDist repositories. - - Base url of repositories is given by configuration variable 'upload_url' - (by default ']] .. cfg.upload_url .. [[') which you can change. - E.g.: Binary version of module 'lua', installed in DEPLOYMENT_DIRECTORY, - will now be uploaded to repository ']] .. cfg.upload_url .. [[lua.git'. - - Organization of uploaded modules and their repositories is subject - to the conventions described in more detail in the source code - of the 'dist.upload_modules()' function (file 'dist/init.lua'). - - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. If no MODULES are specified, all installed modules - will be uploaded. - - You can use * (an asterisk sign) in the name of the module as a wildcard - with the meaning 'any symbols' (in most shells, the module name then must - be quoted to prevent the expansion of asterisk by the shell itself). - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir, modules) - -- check if we have git - local ok = utils.system_dependency_available("git", "git --version") - if not ok then os.exit(1) end - - deploy_dir = deploy_dir or dist.get_deploy_dir() - if type(modules) == "string" then modules = {modules} end - assert(type(deploy_dir) == "string", "luadist.upload: Argument 'deploy_dir' is not a string.") - assert(type(modules) == "table", "luadist.upload: Argument 'modules' is not a string or table.") - deploy_dir = sys.abs_path(deploy_dir) - - local num, err = dist.upload_modules(deploy_dir, modules, cfg.upload_url) - if not num then - print(err) - os.exit(1) - else - print("Uploaded modules: " .. num) - return 0 - end - end - }, - - -- List installed modules. - ["list"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] list [STRINGS...] [-VARIABLES...] - - The 'list' command will list all modules installed in specified - DEPLOYMENT_DIRECTORY, which contain one or more optional STRINGS. - - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. If STRINGS are not specified, all installed modules - are listed. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir, strings) - deploy_dir = deploy_dir or dist.get_deploy_dir() - strings = strings or {} - assert(type(deploy_dir) == "string", "luadist.list: Argument 'deploy_dir' is not a string.") - assert(type(strings) == "table", "luadist.list: Argument 'strings' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - local deployed = dist.get_deployed(deploy_dir) - deployed = depends.filter_packages_by_strings(deployed, strings) - - print("\nInstalled modules:") - print("==================\n") - for _, pkg in pairs(deployed) do - print(" " .. pkg.name .. "-" .. pkg.version .. "\t(" .. pkg.arch .. "-" .. pkg.type .. ")" .. (pkg.provided_by and "\t [provided by " .. pkg.provided_by .. "]" or "")) - end - print() - return 0 - end - }, - - -- Search for modules in repositories. - ["search"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] search [STRINGS...] [-VARIABLES...] - - The 'search' command will list all modules from repositories, which contain - one or more STRINGS. - - If no STRINGS are specified, all available modules are listed. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir, strings) - deploy_dir = deploy_dir or dist.get_deploy_dir() - strings = strings or {} - assert(type(deploy_dir) == "string", "luadist.search: Argument 'deploy_dir' is not a string.") - assert(type(strings) == "table", "luadist.search: Argument 'strings' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - local available, err = mf.get_manifest() - if not available then - print(err) - os.exit(1) - end - - available = depends.filter_packages_by_strings(available, strings) - available = depends.sort_by_names(available) - - print("\nModules found:") - print("==============\n") - for _, pkg in pairs(available) do - print(" " .. pkg.name) - end - print() - return 0 - end - }, - - -- Show information about modules. - ["info"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] info [MODULES...] [-VARIABLES...] - - The 'info' command shows information about specified modules from - repositories. This command also shows whether modules are installed - in DEPLOYMENT_DIRECTORY. - - If no MODULES are specified, all available modules are shown. - If DEPLOYMENT_DIRECTORY is not specified, the deployment directory - of LuaDist is used. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir, modules) - deploy_dir = deploy_dir or dist.get_deploy_dir() - modules = modules or {} - assert(type(deploy_dir) == "string", "luadist.info: Argument 'deploy_dir' is not a string.") - assert(type(modules) == "table", "luadist.info: Argument 'modules' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - local manifest, err = mf.get_manifest() - if not manifest then - print(err) - os.exit(1) - end - - -- if no packages specified explicitly, show just info from .gitmodules for all packages available - if #modules == 0 then - - modules = manifest - modules = depends.sort_by_names(modules) - local deployed = dist.get_deployed(deploy_dir) - - print("") - for _, pkg in pairs(modules) do - print(" " .. pkg.name) - print(" Repository url: " .. (pkg.path or "N/A")) - print() - end - return 0 - - -- if some packages explicitly specified, retrieve and show detailed info about them - else - - if #modules > 5 then - print("NOTE: More than 5 modules specified - operation may take a longer time.") - end - - local deployed = dist.get_deployed(deploy_dir) - - for _, module in pairs(modules) do - manifest, err = package.get_versions_info(module, manifest, deploy_dir, deployed) - if not manifest then - print(err) - os.exit(1) - end - end - - modules = depends.find_packages(modules, manifest) - modules = depends.sort_by_names(modules) - - print("") - for _, pkg in pairs(modules) do - print(" " .. pkg.name .. "-" .. pkg.version .. " (" .. pkg.arch .. "-" .. pkg.type ..")" .. (pkg.from_installed and " [info taken from installed version]" or "")) - print(" Description: " .. (pkg.desc or "N/A")) - print(" Author: " .. (pkg.author or "N/A")) - print(" Homepage: " .. (pkg.url or "N/A")) - print(" License: " .. (pkg.license or "N/A")) - print(" Repository url: " .. (pkg.path or "N/A")) - print(" Maintainer: " .. (pkg.maintainer or "N/A")) - if pkg.provides then print(" Provides: " .. utils.table_tostring(pkg.provides)) end - if pkg.depends then print(" Depends: " .. utils.table_tostring(pkg.depends)) end - if pkg.conflicts then print(" Conflicts: " .. utils.table_tostring(pkg.conflicts)) end - print(" State: " .. (depends.is_installed(pkg.name, deployed, pkg.version) and "installed" or "not installed")) - print() - end - return 0 - end - - end - }, - - -- Print dependency tree. - ["tree"] = { - help = [[ -Usage: luadist [DEPLOYMENT_DIRECTORY] tree [MODULES...] [-VARIABLES...] - - The 'tree' command prints dependency tree for specified modules. - - If no MODULES are specified, trees for all available modules are printed. - This information about modules is being cached in dependency manifest. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (deploy_dir, modules) - deploy_dir = deploy_dir or dist.get_deploy_dir() - modules = modules or {} - assert(type(deploy_dir) == "string", "luadist.info: Argument 'deploy_dir' is not a string.") - assert(type(modules) == "table", "luadist.info: Argument 'modules' is not a table.") - deploy_dir = sys.abs_path(deploy_dir) - - local manifest, err = mf.get_manifest() - if not manifest then - print(err) - os.exit(1) - end - - -- if no modules specified explicitly, assume all modules - if #modules == 0 then modules = depends.sort_by_names(manifest) end - print("Getting dependency information... (this may take a lot of time)") - - for _, module in pairs(modules) do - - -- if all modules are being queried, extract the name - if type(module) == "table" then module = module.name end - - local dep_manifest, err = dist.dependency_info(module, deploy_dir) - if not dep_manifest then - print(err) - os.exit(1) - else - - -- print the dependency tree - local heading = "Dependency tree for '" .. module .. "' (on " .. cfg.arch .. "-" .. cfg.type .. "):" - print("\n" .. heading .. "") - print(string.rep("=", #heading) .. "\n") - - for _, pkg in pairs(dep_manifest) do - - local pkg_version, pkg_tag = pkg.version, pkg.version - if pkg.was_scm_version then - pkg_version, pkg_tag = "scm", "HEAD" - end - print(" " .. pkg.name .. "-" .. pkg_version .. " (" .. pkg.path .. ", " .. pkg_tag .. ")") - if pkg.depends then - for _, dep in pairs(pkg.depends) do - if type(dep) ~= "table" then - local found = depends.sort_by_versions(depends.find_packages(dep, dep_manifest))[1] - if not found then - print("Could not find the dependency '" .. dep .. "' in the dependency manifest.") - os.exit(1) - end - print(" * " .. found.name .. "-" .. found.version .. " (" .. found.path .. ", " .. found.version .. ")") - end - end - end - print() - end - - end - end - return 0 - - end - }, - - -- Selftest of LuaDist. - ["selftest"] = { - help = [[ -Usage: luadist [TEST_DIRECTORY] selftest [-VARIABLES...] - - The 'selftest' command runs tests of LuaDist, located in TEST_DIRECTORY and - displays the results. - - If no TEST_DIRECTORY is specified, the default test directory of LuaDist - deployment directory (i.e. ']] .. cfg.test_dir .. [[') is used. - - Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be - specified. - ]], - - run = function (test_dir) - test_dir = test_dir or dist.get_deploy_dir() - assert(type(test_dir) == "string", "luadist.selftest: Argument 'deploy_dir' is not a string.") - test_dir = sys.abs_path(test_dir) - - -- if the default parameter (i.e. deploy_dir) is passed, use the default test_dir - if test_dir == dist.get_deploy_dir() then - test_dir = sys.make_path(test_dir, cfg.test_dir) - end - - -- try to get an iterator over test files and check it - local test_iterator, err = sys.get_directory(test_dir) - if not test_iterator then - print("Running tests from '" .. test_dir .. "' failed: " .. err) - os.exit(1) - end - - -- run the tests - print("\nRunning tests:") - print("==============") - for test_file in sys.get_directory(test_dir) do - test_file = sys.make_path(test_dir, test_file) - if sys.is_file(test_file) then - print() - print(sys.extract_name(test_file) .. ":") - dofile(test_file) - end - end - print() - return 0 - end - }, -} - --- Run the functionality of LuaDist 'command' in the 'deploy_dir' with other items --- or settings/variables starting at 'other_idx' index of special variable 'arg'. -local function run_command(deploy_dir, command, other_idx) - deploy_dir = deploy_dir or dist.get_deploy_dir() - assert(type(deploy_dir) == "string", "luadist.run_command: Argument 'deploy_dir' is not a string.") - assert(type(command) == "string", "luadist.run_command: Argument 'command' is not a string.") - assert(not other_idx or type(other_idx) == "number", "luadist.run_command: Argument 'other_idx' is not a number.") - deploy_dir = sys.abs_path(deploy_dir) - - local items = {} - local cmake_variables = {} - - -- parse items after the command (and LuaDist or CMake variables) - if other_idx then - for i = other_idx, #arg do - - -- CMake variable - if arg[i]:match("^%-D(.-)=(.*)$") then - local variable, value = arg[i]:match("^%-D(.-)=(.*)$") - cmake_variables[variable] = value - - -- LuaDist variable - elseif arg[i]:match("^%-(.-)=(.*)$") then - local variable, value = arg[i]:match("^%-(.-)=(.*)$") - apply_settings(variable, value) - - -- LuaDist boolean variable with implicit 'true' value - elseif arg[i]:match("^%-(.-)$") then - local variable, value = arg[i]:match("^%-(.-)$") - apply_settings(variable, "true") - - -- not a LuaDist or CMake variable - else - table.insert(items, arg[i]) - end - end - end - - -- run the required LuaDist functionality - return commands[command].run(sys.abs_path(deploy_dir), items, cmake_variables) -end - --- Print information about Luadist (version, license, etc.). -function print_info() - print([[ -LuaDist-git ]].. cfg.version .. [[ - Lua package manager for the LuaDist deployment system. -Released under the MIT License. See https://github.com/luadist/luadist-git - ]]) - return 0 -end - --- Convenience function for printing the main luadist help. -function print_help() - return run_command(nil, "help") -end - --- Set the LuaDist 'variable' to the 'value'. --- See available settings in 'dist.config' module. -function apply_settings(variable, value) - assert(type(variable) == "string", "luadist.apply_settings: Argument 'variable' is not a string.") - assert(type(value) == "string", "luadist.apply_settings: Argument 'value' is not a string.") - - -- check whether the settings variable exists - if cfg[variable] == nil then - print("Unknown LuaDist configuration option: '" .. variable .. "'.") - os.exit(1) - - -- ensure the right type - - elseif type(cfg[variable]) == "boolean" then - value = value:lower() - if value == "true" or value == "yes" or value == "on" or value == "1" then - value = true - elseif value == "false" or value == "no" or value == "off" or value == "0" then - value = false - else - print("Value of LuaDist option '" .. variable .. "' must be a boolean.") - os.exit(1) - end - - elseif type(cfg[variable]) == "number" then - value = tonumber(value) - if not value then - print("Value of LuaDist option '" .. variable .. "' must be a number.") - os.exit(1) - end - - elseif type(cfg[variable]) == "table" then - local err - value, err = utils.make_table(value, ",") - if not value then - print("Error when parsing the LuaDist variable '" .. variable .. "': " .. err) - os.exit(1) - end - end - - -- set the LuaDist variable - cfg[variable] = value - -end - --- Parse command line input and run the required command. -if pcall(debug.getlocal, 4, 1) then - return commands -- return commands when used as module -elseif not commands[arg[1]] and commands[arg[2]] then - -- deploy_dir specified - return run_command(arg[1], arg[2], 3) -elseif commands[arg[1]] then - -- deploy_dir not specified - return run_command(dist.get_deploy_dir(), arg[1], 2) -else - -- unknown command - if arg[1] then - print("Unknown command '" .. arg[1] .. "'. Printing help...\n") - print_help() - os.exit(1) - end - return print_help() -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/ast.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/ast.lua deleted file mode 100644 index 12244d9..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/ast.lua +++ /dev/null @@ -1,915 +0,0 @@ --- luainspect.ast - Lua Abstract Syntax Tree (AST) and token list operations. --- --- Two main structures are maintained. A Metalua-style AST represents the --- nested syntactic structure obtained from the parse. --- A separate linear ordered list of tokens represents the syntactic structure --- from the lexing, including line information (character positions only not row/columns), --- comments, and keywords, which is originally built from the lineinfo attributes --- injected by Metalua into the AST (IMPROVE: it probably would be simpler --- to obtain this from the lexer directly rather then inferring it from the parsing). --- During AST manipulations, the lineinfo maintained in the AST is ignored --- because it was found more difficult to maintain and not in the optimal format. --- --- The contained code deals with --- - Building the AST from source. --- - Building the tokenlist from the AST lineinfo. --- - Querying the AST+tokenlist. --- - Modifying the AST+tokenlist (including incremental parsing source -> AST) --- - Annotating the AST with navigational info (e.g. parent links) to assist queries. --- - Dumping the tokenlist for debugging. --- --- (c) 2010 David Manura, MIT License. - - ---! require 'luainspect.typecheck' (context) - -local mlc = require 'metalua.compiler'.new() - -local M = {} - ---[=TESTSUITE --- utilities -local ops = {} -ops['=='] = function(a,b) return a == b end -local function check(opname, a, b) - local op = assert(ops[opname]) - if not op(a,b) then - error("fail == " .. tostring(a) .. " " .. tostring(b)) - end -end ---]=] - --- CATEGORY: debug -local function DEBUG(...) - if LUAINSPECT_DEBUG then - print('DEBUG:', ...) - end -end - - --- Converts character position to row,column position in string src. --- Add values are 1-indexed. -function M.pos_to_linecol(pos, src) - local linenum = 1 - local lasteolpos = 0 - for eolpos in src:gmatch"()\n" do - if eolpos > pos then break end - linenum = linenum + 1 - lasteolpos = eolpos - end - local colnum = pos - lasteolpos - return linenum, colnum -end - --- Removes any sheband ("#!") line from Lua source string. --- CATEGORY: Lua parsing -function M.remove_shebang(src) - local shebang = src:match("^#![^\r\n]*") - return shebang and (" "):rep(#shebang) .. src:sub(#shebang+1) or src -end - - --- Custom version of loadstring that parses out line number info --- CATEGORY: Lua parsing -function M.loadstring(src) - local f, err = loadstring(src, "") - if f then - return f - else - err = err:gsub('^%[string ""%]:', "") - local linenum = assert(err:match("(%d+):")) - local colnum = 0 - local linenum2 = err:match("^%d+: '[^']+' expected %(to close '[^']+' at line (%d+)") - return nil, err, linenum, colnum, linenum2 - end -end - - --- helper for ast_from_string. Raises on error. --- FIX? filename currently ignored in Metalua --- CATEGORY: Lua parsing -local function ast_from_string_helper(src, filename) - return mlc:src_to_ast(src, filename) -end - - --- Counts number of lines in text. --- Warning: the decision of whether to count a trailing new-line in a file --- or an empty file as a line is a little subjective. This function currently --- defines the line count as 1 plus the number of new line characters. --- CATEGORY: utility/string -local function linecount(text) - local n = 1 - for _ in text:gmatch'\n' do - n = n + 1 - end - return n -end - - --- Converts Lua source string to Lua AST (via mlp/gg). --- CATEGORY: Lua parsing -function M.ast_from_string(src, filename) - local ok, ast = pcall(ast_from_string_helper, src, filename) - if not ok then - local err = ast - err = err:match('[^\n]*') - err = err:gsub("^.-:%s*line", "line") - -- mlp.chunk prepending this is undesirable. error(msg,0) would be better in gg.lua. Reported. - -- TODO-Metalua: remove when fixed in Metalua. - local linenum, colnum = err:match("line (%d+), char (%d+)") - if not linenum then - -- Metalua libraries may return "...gg.lua:56: .../mlp_misc.lua:179: End-of-file expected" - -- without the normal line/char numbers given things like "if x then end end". Should be - -- fixed probably with gg.parse_error in _chunk in mlp_misc.lua. - -- TODO-Metalua: remove when fixed in Metalua. - linenum = linecount(src) - colnum = 1 - end - local linenum2 = nil - return nil, err, linenum, colnum, linenum2 - else - return ast - end -end - - --- Simple comment parser. Returns Metalua-style comment. --- CATEGORY: Lua lexing -local function quick_parse_comment(src) - local s = src:match"^%-%-([^\n]*)()\n$" - if s then return {s, 1, #src, 'short'} end - local _, s = src:match(lexer.lexer.patterns.long_comment .. '\r?\n?$') - if s then return {s, 1, #src, 'long'} end - return nil -end ---FIX:check new-line correctness ---note: currently requiring \n at end of single line comment to avoid --- incremental compilation with `--x\nf()` and removing \n from still --- recognizing as comment `--x`. --- currently allowing \r\n at end of long comment since Metalua includes --- it in lineinfo of long comment (FIX:Metalua?) - - --- Gets length of longest prefix string in both provided strings. --- Returns max n such that text1:sub(1,n) == text2:sub(1,n) and n <= max(#text1,#text2) --- CATEGORY: string utility -local function longest_prefix(text1, text2) - local nmin = 0 - local nmax = math.min(#text1, #text2) - while nmax > nmin do - local nmid = math.ceil((nmin+nmax)/2) - if text1:sub(1,nmid) == text2:sub(1,nmid) then - nmin = nmid - else - nmax = nmid-1 - end - end - return nmin -end - - --- Gets length of longest postfix string in both provided strings. --- Returns max n such that text1:sub(-n) == text2:sub(-n) and n <= max(#text1,#text2) --- CATEGORY: string utility -local function longest_postfix(text1, text2) - local nmin = 0 - local nmax = math.min(#text1, #text2) - while nmax > nmin do - local nmid = math.ceil((nmin+nmax)/2) - if text1:sub(-nmid) == text2:sub(-nmid) then --[*] - nmin = nmid - else - nmax = nmid-1 - end - end - return nmin -end -- differs from longest_prefix only on line [*] - - - --- Determines AST node that must be re-evaluated upon changing code string from --- `src` to `bsrc`, given previous top_ast/tokenlist/src. --- Note: decorates top_ast as side-effect. --- If preserve is true, then does not expand AST match even if replacement is invalid. --- CATEGORY: AST/tokenlist manipulation -function M.invalidated_code(top_ast, tokenlist, src, bsrc, preserve) - -- Converts posiiton range in src to position range in bsrc. - local function range_transform(src_fpos, src_lpos) - local src_nlpos = #src - src_lpos - local bsrc_fpos = src_fpos - local bsrc_lpos = #bsrc - src_nlpos - return bsrc_fpos, bsrc_lpos - end - - if src == bsrc then return end -- up-to-date - - -- Find range of positions in src that differences correspond to. - -- Note: for zero byte range, src_pos2 = src_pos1 - 1. - local npre = longest_prefix(src, bsrc) - local npost = math.min(#src-npre, longest_postfix(src, bsrc)) - -- note: min avoids overlap ambiguity - local src_fpos, src_lpos = 1 + npre, #src - npost - - -- Find smallest AST node containing src range above. May also - -- be contained in (smaller) comment or whitespace. - local match_ast, match_comment, iswhitespace = - M.smallest_ast_containing_range(top_ast, tokenlist, src_fpos, src_lpos) - DEBUG('invalidate-smallest:', match_ast and (match_ast.tag or 'notag'), match_comment, iswhitespace) - - -- Determine which (ast, comment, or whitespace) to match, and get its pos range in src and bsrc. - local srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype - if iswhitespace then - mast, mtype = nil, 'whitespace' - srcm_fpos, srcm_lpos = src_fpos, src_lpos - elseif match_comment then - mast, mtype = match_comment, 'comment' - srcm_fpos, srcm_lpos = match_comment.fpos, match_comment.lpos - else - mast, mtype = match_ast, 'ast' - repeat - srcm_fpos, srcm_lpos = M.ast_pos_range(mast, tokenlist) - if not srcm_fpos then - if mast == top_ast then - srcm_fpos, srcm_lpos = 1, #src - break - else - M.ensure_parents_marked(top_ast) - mast = mast.parent - end - end - until srcm_fpos - end - bsrcm_fpos, bsrcm_lpos = range_transform(srcm_fpos, srcm_lpos) - - -- Never expand match if preserve specified. - if preserve then - return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype - end - - -- Determine if replacement could break parent nodes. - local isreplacesafe - if mtype == 'whitespace' then - if bsrc:sub(bsrcm_fpos, bsrcm_lpos):match'^%s*$' then -- replaced with whitespace - if bsrc:sub(bsrcm_fpos-1, bsrcm_lpos+1):match'%s' then -- not eliminating whitespace - isreplacesafe = true - end - end - elseif mtype == 'comment' then - local m2src = bsrc:sub(bsrcm_fpos, bsrcm_lpos) - DEBUG('invalidate-comment[' .. m2src .. ']') - if quick_parse_comment(m2src) then -- replaced with comment - isreplacesafe = true - end - end - if isreplacesafe then -- return on safe replacement - return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype - end - - -- Find smallest containing statement block that will compile (or top_ast). - while 1 do - match_ast = M.get_containing_statementblock(match_ast, top_ast) - if match_ast == top_ast then - return 1,#src, 1, #bsrc, match_ast, 'statblock' - -- entire AST invalidated - end - local srcm_fpos, srcm_lpos = M.ast_pos_range(match_ast, tokenlist) - local bsrcm_fpos, bsrcm_lpos = range_transform(srcm_fpos, srcm_lpos) - local msrc = bsrc:sub(bsrcm_fpos, bsrcm_lpos) - DEBUG('invalidate-statblock:', match_ast and match_ast.tag, '[' .. msrc .. ']') - if loadstring(msrc) then -- compiled - return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, match_ast, 'statblock' - end - M.ensure_parents_marked(top_ast) - match_ast = match_ast.parent - end -end - - --- Walks AST `ast` in arbitrary order, visiting each node `n`, executing `fdown(n)` (if specified) --- when doing down and `fup(n)` (if specified) when going if. --- CATEGORY: AST walk -function M.walk(ast, fdown, fup) - assert(type(ast) == 'table') - if fdown then fdown(ast) end - for _,bast in ipairs(ast) do - if type(bast) == 'table' then - M.walk(bast, fdown, fup) - end - end - if fup then fup(ast) end -end - - --- Replaces contents of table t1 with contents of table t2. --- Does not change metatable (if any). --- This function is useful for swapping one AST node with another --- while preserving any references to the node. --- CATEGORY: table utility -function M.switchtable(t1, t2) - for k in pairs(t1) do t1[k] = nil end - for k in pairs(t2) do t1[k] = t2[k] end -end - - --- Inserts all elements in list bt at index i in list t. --- CATEGORY: table utility -local function tinsertlist(t, i, bt) - local oldtlen, delta = #t, i - 1 - for ti = #t + 1, #t + #bt do t[ti] = false end -- preallocate (avoid holes) - for ti = oldtlen, i, -1 do t[ti + #bt] = t[ti] end -- shift - for bi = 1, #bt do t[bi + delta] = bt[bi] end -- fill -end ---[=[TESTSUITE: -local function _tinsertlist(t, i, bt) - for bi=#bt,1,-1 do table.insert(t, i, bt[bi]) end -end -- equivalent but MUCH less efficient for large tables -local function _tinsertlist(t, i, bt) - for bi=1,#bt do table.insert(t, i+bi-1, bt[bi]) end -end -- equivalent but MUCH less efficient for large tables -local t = {}; tinsertlist(t, 1, {}); assert(table.concat(t)=='') -local t = {}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='23') -local t = {4}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='234') -local t = {2}; tinsertlist(t, 2, {3,4}); assert(table.concat(t)=='234') -local t = {4,5}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='2345') -local t = {2,5}; tinsertlist(t, 2, {3,4}); assert(table.concat(t)=='2345') -local t = {2,3}; tinsertlist(t, 3, {4,5}); assert(table.concat(t)=='2345') -print 'DONE' ---]=] - - - --- Gets list of keyword positions related to node ast in source src --- note: ast must be visible, i.e. have lineinfo (e.g. unlike `Id "self" definition). --- Note: includes operators. --- Note: Assumes ast Metalua-style lineinfo is valid. --- CATEGORY: tokenlist build -function M.get_keywords(ast, src) - local list = {} - if not ast.lineinfo then return list end - -- examine space between each pair of children i and j. - -- special cases: 0 is before first child and #ast+1 is after last child - - -- Put children in lexical order. - -- Some binary operations have arguments reversed from lexical order. - -- For example, `a > b` becomes `Op{'lt', `Id 'b', `Id 'a'} - local oast = - (ast.tag == 'Op' and #ast == 3 and tostring(ast[2].lineinfo.first):match('|L(%d+)') > tostring(ast[3].lineinfo.first):match('|L(%d+)')) - and {ast[1], ast[3], ast[2]} or ast - - local i = 0 - while i <= #ast do - -- j is node following i that has lineinfo - local j = i+1; while j < #ast+1 and not oast[j].lineinfo do j=j+1 end - - -- Get position range [fpos,lpos] between subsequent children. - local fpos - if i == 0 then -- before first child - fpos = tonumber(tostring(ast.lineinfo.first):match('|L(%d+)')) - else - local last = oast[i].lineinfo.last; local c = last.comments - fpos = (c and #c > 0 and c[#c][3] or tostring(last):match('|L(%d+)')) + 1 - end - local lpos - if j == #ast+1 then -- after last child - lpos = tonumber(tostring(ast.lineinfo.last):match('|L(%d+)')) - else - local first = oast[j].lineinfo.first; local c = first.comments - lpos = (c and #c > 0 and c[1][2] or tostring(first):match('|L(%d+)')) - 1 - end - - -- Find keyword in range. - local spos = fpos - repeat - local mfpos, tok, mlppos = src:match("^%s*()(%a+)()", spos) - if not mfpos then - mfpos, tok, mlppos = src:match("^%s*()(%p+)()", spos) - end - if mfpos then - local mlpos = mlppos-1 - if mlpos > lpos then mlpos = lpos end - if mlpos >= mfpos then - list[#list+1] = mfpos - list[#list+1] = mlpos - end - end - spos = mlppos - until not spos or spos > lpos - -- note: finds single keyword. in `local function` returns only `local` - --DEBUG(i,j ,'test[' .. src:sub(fpos, lpos) .. ']') - - i = j -- next - - --DESIGN:Lua: comment: string.match accepts a start position but not a stop position - end - return list -end --- Q:Metalua: does ast.lineinfo[loc].comments imply #ast.lineinfo[loc].comments > 0 ? - - - --- Generates ordered list of tokens in top_ast/src. --- Note: currently ignores operators and parens. --- Note: Modifies ast. --- Note: Assumes ast Metalua-style lineinfo is valid. --- CATEGORY: AST/tokenlist query -local isterminal = {Nil=true, Dots=true, True=true, False=true, Number=true, String=true, - Dots=true, Id=true} -local function compare_tokens_(atoken, btoken) return atoken.fpos < btoken.fpos end -function M.ast_to_tokenlist(top_ast, src) - local tokens = {} -- {nbytes=#src} - local isseen = {} - M.walk(top_ast, function(ast) - if isterminal[ast.tag] then -- Extract terminal - local token = ast - if ast.lineinfo then - token.fpos = tonumber(tostring(ast.lineinfo.first):match('|L(%d+)')) - token.lpos = tonumber(tostring(ast.lineinfo.last):match('|L(%d+)')) - token.ast = ast - table.insert(tokens, token) - end - else -- Extract non-terminal - local keywordposlist = M.get_keywords(ast, src) - for i=1,#keywordposlist,2 do - local fpos, lpos = keywordposlist[i], keywordposlist[i+1] - local toksrc = src:sub(fpos, lpos) - local token = {tag='Keyword', fpos=fpos, lpos=lpos, ast=ast, toksrc} - table.insert(tokens, token) - end - end - -- Extract comments - for i=1,2 do - local comments = ast.lineinfo and ast.lineinfo[i==1 and 'first' or 'last'].comments - if comments then for _, comment in ipairs(comments) do - if not isseen[comment] then - comment.tag = 'Comment' - local token = comment - token.fpos = tonumber(tostring(comment.lineinfo.first):match('|L(%d+)')) - token.lpos = tonumber(tostring(comment.lineinfo.last):match('|L(%d+)')) - token.ast = comment - table.insert(tokens, token) - isseen[comment] = true - end - end end - end - end, nil) - table.sort(tokens, compare_tokens_) - return tokens -end - - --- Gets tokenlist range [fidx,lidx] covered by ast. Returns nil,nil if not found. ---FIX:PERFORMANCE:this is slow on large files. --- CATEGORY: AST/tokenlist query -function M.ast_idx_range_in_tokenlist(tokenlist, ast) - -- Get list of primary nodes under ast. - local isold = {}; M.walk(ast, function(ast) isold[ast] = true end) - -- Get range. - local fidx, lidx - for idx=1,#tokenlist do - local token = tokenlist[idx] - if isold[token.ast] then - lidx = idx - if not fidx then fidx = idx end - end - end - return fidx, lidx -end - - --- Gets index range in tokenlist overlapped by character position range [fpos, lpos]. --- For example, `do ff() end` with range ` ff() ` would match tokens `ff()`. --- Tokens partly inside range are counted, so range `f()` would match tokens `ff()`. --- If lidx = fidx - 1, then position range is whitespace between tokens lidx (on left) --- and fidx (on right), and this may include token pseudoindices 0 (start of file) and --- #tokenlist+1 (end of file). --- Note: lpos == fpos - 1 indicates zero-width range between chars lpos and fpos. --- CATEGORY: tokenlist query -function M.tokenlist_idx_range_over_pos_range(tokenlist, fpos, lpos) - -- Find first/last indices of tokens overlapped (even partly) by position range. - local fidx, lidx - for idx=1,#tokenlist do - local token = tokenlist[idx] - --if (token.fpos >= fpos and token.fpos <= lpos) or (token.lpos >= fpos and token.lpos <= lpos) then -- token overlaps range - if fpos <= token.lpos and lpos >= token.fpos then -- range overlaps token (even partially) - if not fidx then fidx = idx end - lidx = idx - end - end - if not fidx then -- on fail, check between tokens - for idx=1,#tokenlist+1 do -- between idx-1 and idx - local tokfpos, toklpos = tokenlist[idx-1] and tokenlist[idx-1].lpos, tokenlist[idx] and tokenlist[idx].fpos - if (not tokfpos or fpos > tokfpos) and (not toklpos or lpos < toklpos) then -- range between tokens - return idx, idx-1 - end - end - end - return fidx, lidx -end ---[=[TESTSUITE -local function test(...) - return table.concat({M.tokenlist_idx_range_over_pos_range(...)}, ',') -end -check('==', test({}, 2, 2), "1,0") -- no tokens -check('==', test({{tag='Id', fpos=1, lpos=1}}, 2, 2), "2,1") -- right of one token -check('==', test({{tag='Id', fpos=3, lpos=3}}, 2, 2), "1,0") -- left of one token -check('==', test({{tag='Id', fpos=3, lpos=4}}, 2, 3), "1,1") -- left partial overlap one token -check('==', test({{tag='Id', fpos=3, lpos=4}}, 4, 5), "1,1") -- right partial overlap one token -check('==', test({{tag='Id', fpos=3, lpos=6}}, 4, 5), "1,1") -- partial inner overlap one token -check('==', test({{tag='Id', fpos=3, lpos=6}}, 3, 6), "1,1") -- exact overlap one token -check('==', test({{tag='Id', fpos=4, lpos=5}}, 3, 6), "1,1") -- extra overlap one token -check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 4, 4), "2,1") -- between tokens, " " exact -check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 4, 3), "2,1") -- between tokens, "" on left -check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 5, 4), "2,1") -- between tokens, "" on right -check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=4, lpos=5}}, 4, 3), "2,1") -- between tokens, "" exact ---]=] - --- Removes tokens in tokenlist covered by ast. --- CATEGORY: tokenlist manipulation -local function remove_ast_in_tokenlist(tokenlist, ast) - local fidx, lidx = M.ast_idx_range_in_tokenlist(tokenlist, ast) - if fidx then -- note: fidx implies lidx - for idx=lidx,fidx,-1 do table.remove(tokenlist, idx) end - end -end - - --- Inserts tokens from btokenlist into tokenlist. Preserves sort. --- CATEGORY: tokenlist manipulation -local function insert_tokenlist(tokenlist, btokenlist) - local ftoken = btokenlist[1] - if ftoken then - -- Get index in tokenlist in which to insert tokens in btokenlist. - local fidx - for idx=1,#tokenlist do - if tokenlist[idx].fpos > ftoken.fpos then fidx = idx; break end - end - fidx = fidx or #tokenlist + 1 -- else append - - -- Insert tokens. - tinsertlist(tokenlist, fidx, btokenlist) - end -end - - --- Get character position range covered by ast in tokenlist. Returns nil,nil on not found. --- CATEGORY: AST/tokenlist query -function M.ast_pos_range(ast, tokenlist) -- IMPROVE:style: ast_idx_range_in_tokenlist has params reversed - local fidx, lidx = M.ast_idx_range_in_tokenlist(tokenlist, ast) - if fidx then - return tokenlist[fidx].fpos, tokenlist[lidx].lpos - else - return nil, nil - end -end - - --- Gets string representation of AST node. nil if none. --- IMPROVE: what if node is empty block? --- CATEGORY: AST/tokenlist query -function M.ast_to_text(ast, tokenlist, src) -- IMPROVE:style: ast_idx_range_in_tokenlist has params reversed - local fpos, lpos = M.ast_pos_range(ast, tokenlist) - if fpos then - return src:sub(fpos, lpos) - else - return nil - end -end - - - --- Gets smallest AST node in top_ast/tokenlist/src --- completely containing position range [pos1, pos2]. --- careful: "function" is not part of the `Function node. --- If range is inside comment, returns comment also. --- If range is inside whitespace, then returns true in third return value. --- CATEGORY: AST/tokenlist query -function M.smallest_ast_containing_range(top_ast, tokenlist, pos1, pos2) - local f0idx, l0idx = M.tokenlist_idx_range_over_pos_range(tokenlist, pos1, pos2) - - -- Find enclosing AST. - M.ensure_parents_marked(top_ast) - local fidx, lidx = f0idx, l0idx - while tokenlist[fidx] and not tokenlist[fidx].ast.parent do fidx = fidx - 1 end - while tokenlist[lidx] and not tokenlist[lidx].ast.parent do lidx = lidx + 1 end - -- DEBUG(fidx, lidx, f0idx, l0idx, #tokenlist, pos1, pos2, tokenlist[fidx], tokenlist[lidx]) - local ast = not (tokenlist[fidx] and tokenlist[lidx]) and top_ast or - M.common_ast_parent(tokenlist[fidx].ast, tokenlist[lidx].ast, top_ast) - -- DEBUG('m2', tokenlist[fidx], tokenlist[lidx], top_ast, ast, ast and ast.tag) - if l0idx == f0idx - 1 then -- whitespace - return ast, nil, true - elseif l0idx == f0idx and tokenlist[l0idx].tag == 'Comment' then - return ast, tokenlist[l0idx], nil - else - return ast, nil, nil - end -end ---IMPROVE: handle string edits and maybe others - - --- Gets smallest statement block containing position pos or --- nearest statement block before pos, whichever is smaller, given ast/tokenlist. -function M.current_statementblock(ast, tokenlist, pos) - local fidx,lidx = M.tokenlist_idx_range_over_pos_range(tokenlist, pos, pos) - if fidx > lidx then fidx = lidx end -- use nearest backward - - -- Find closest AST node backward - while fidx >= 1 and tokenlist[fidx].tag == 'Comment' do fidx=fidx-1 end - - if fidx < 1 then return ast, false end - local mast = tokenlist[fidx].ast - if not mast then return ast, false end - mast = M.get_containing_statementblock(mast, ast) - local isafter = false - if mast.tag2 ~= 'Block' then - local mfidx,mlidx = M.ast_idx_range_in_tokenlist(tokenlist, mast) - if pos > mlidx then - isafter = true - end - end - - return mast, isafter -end - --- Gets index of bast in ast (nil if not found). --- CATEGORY: AST query -function M.ast_idx(ast, bast) - for idx=1,#ast do - if ast[idx] == bast then return idx end - end - return nil -end - - --- Gets parent of ast and index of ast in parent. --- Root node top_ast must also be provided. Returns nil, nil if ast is root. --- Note: may call mark_parents. --- CATEGORY: AST query -function M.ast_parent_idx(top_ast, ast) - if ast == top_ast then return nil, nil end - M.ensure_parents_marked(top_ast); assert(ast.parent) - local idx = M.ast_idx(ast.parent, ast) - return ast.parent, idx -end - - --- Gets common parent of aast and bast. Always returns value. --- Must provide root top_ast too. --- CATEGORY: AST query -function M.common_ast_parent(aast, bast, top_ast) - M.ensure_parents_marked(top_ast) - local isparent = {} - local tast = bast; repeat isparent[tast] = true; tast = tast.parent until not tast - local uast = aast; repeat if isparent[uast] then return uast end; uast = uast.parent until not uast - assert(false) -end - - --- Replaces old_ast with new_ast/new_tokenlist in top_ast/tokenlist. --- Note: assumes new_ast is a block. assumes old_ast is a statement or block. --- CATEGORY: AST/tokenlist -function M.replace_statements(top_ast, tokenlist, old_ast, new_ast, new_tokenlist) - remove_ast_in_tokenlist(tokenlist, old_ast) - insert_tokenlist(tokenlist, new_tokenlist) - if old_ast == top_ast then -- special case: no parent - M.switchtable(old_ast, new_ast) -- note: safe since block is not in tokenlist. - else - local parent_ast, idx = M.ast_parent_idx(top_ast, old_ast) - table.remove(parent_ast, idx) - tinsertlist(parent_ast, idx, new_ast) - end - - -- fixup annotations - for _,bast in ipairs(new_ast) do - if top_ast.tag2 then M.mark_tag2(bast, bast.tag == 'Do' and 'StatBlock' or 'Block') end - if old_ast.parent then M.mark_parents(bast, old_ast.parent) end - end -end - - --- Adjusts lineinfo in tokenlist. --- All char positions starting at pos1 are shifted by delta number of chars. --- CATEGORY: tokenlist -function M.adjust_lineinfo(tokenlist, pos1, delta) - for _,token in ipairs(tokenlist) do - if token.fpos >= pos1 then - token.fpos = token.fpos + delta - end - if token.lpos >= pos1 then - token.lpos = token.lpos + delta - end - end - --tokenlist.nbytes = tokenlist.nbytes + delta -end - - --- For each node n in ast, sets n.parent to parent node of n. --- Assumes ast.parent will be parent_ast (may be nil) --- CATEGORY: AST query -function M.mark_parents(ast, parent_ast) - ast.parent = parent_ast - for _,ast2 in ipairs(ast) do - if type(ast2) == 'table' then - M.mark_parents(ast2, ast) - end - end -end - - --- Calls mark_parents(ast) if ast not marked. --- CATEGORY: AST query -function M.ensure_parents_marked(ast) - if ast[1] and not ast[1].parent then M.mark_parents(ast) end -end - - --- For each node n in ast, sets n.tag2 to context string: --- 'Block' - node is block --- 'Stat' - node is statement --- 'StatBlock' - node is statement and block (i.e. `Do) --- 'Exp' - node is expression --- 'Explist' - node is expression list (or identifier list) --- 'Pair' - node is key-value pair in table constructor --- note: ast.tag2 will be set to context. --- CATEGORY: AST query -local iscertainstat = {Do=true, Set=true, While=true, Repeat=true, If=true, - Fornum=true, Forin=true, Local=true, Localrec=true, Return=true, Break=true} -function M.mark_tag2(ast, context) - context = context or 'Block' - ast.tag2 = context - for i,bast in ipairs(ast) do - if type(bast) == 'table' then - local nextcontext - if bast.tag == 'Do' then - nextcontext = 'StatBlock' - elseif iscertainstat[bast.tag] then - nextcontext = 'Stat' - elseif bast.tag == 'Call' or bast.tag == 'Invoke' then - nextcontext = context == 'Block' and 'Stat' or 'Exp' - --DESIGN:Metalua: these calls actually contain expression lists, - -- but the expression list is not represented as a complete node - -- by Metalua (as blocks are in `Do statements) - elseif bast.tag == 'Pair' then - nextcontext = 'Pair' - elseif not bast.tag then - if ast.tag == 'Set' or ast.tag == 'Local' or ast.tag == 'Localrec' - or ast.tag == 'Forin' and i <= 2 - or ast.tag == 'Function' and i == 1 - then - nextcontext = 'Explist' - else - nextcontext = 'Block' - end - else - nextcontext = 'Exp' - end - M.mark_tag2(bast, nextcontext) - end - end -end - - --- Gets smallest statement or block containing or being `ast`. --- The AST root node `top_ast` must also be provided. --- Note: may decorate AST as side-effect (mark_tag2/mark_parents). --- top_ast is assumed a block, so this is always successful. --- CATEGORY: AST query -function M.get_containing_statementblock(ast, top_ast) - if not top_ast.tag2 then M.mark_tag2(top_ast) end - if ast.tag2 == 'Stat' or ast.tag2 == 'StatBlock' or ast.tag2 == 'Block' then - return ast - else - M.ensure_parents_marked(top_ast) - return M.get_containing_statementblock(ast.parent, top_ast) - end -end - - --- Finds smallest statement, block, or comment AST in ast/tokenlist containing position --- range [fpos, lpos]. If allowexpand is true (default nil) and located AST --- coincides with position range, then next containing statement is used --- instead (this allows multiple calls to further expand the statement selection). --- CATEGORY: AST query -function M.select_statementblockcomment(ast, tokenlist, fpos, lpos, allowexpand) ---IMPROVE: rename ast to top_ast - local match_ast, comment_ast = M.smallest_ast_containing_range(ast, tokenlist, fpos, lpos) - local select_ast = comment_ast or M.get_containing_statementblock(match_ast, ast) - local nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist) - --DEBUG('s', nfpos, nlpos, fpos, lpos, match_ast.tag, select_ast.tag) - if allowexpand and fpos == nfpos and lpos == nlpos then - if comment_ast then - -- Select enclosing statement. - select_ast = match_ast - nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist) - else - -- note: multiple times may be needed to expand selection. For example, in - -- `for x=1,2 do f() end` both the statement `f()` and block `f()` have - -- the same position range. - M.ensure_parents_marked(ast) - while select_ast.parent and fpos == nfpos and lpos == nlpos do - select_ast = M.get_containing_statementblock(select_ast.parent, ast) - nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist) - end - end - end - return nfpos, nlpos -end - - --- Converts tokenlist to string representation for debugging. --- CATEGORY: tokenlist debug -function M.dump_tokenlist(tokenlist) - local ts = {} - for i,token in ipairs(tokenlist) do - ts[#ts+1] = 'tok.' .. i .. ': [' .. token.fpos .. ',' .. token.lpos .. '] ' - .. tostring(token[1]) .. ' ' .. tostring(token.ast.tag) - end - return table.concat(ts, '\n') -- .. 'nbytes=' .. tokenlist.nbytes .. '\n' -end - - ---FIX:Q: does this handle Unicode ok? - ---FIX?:Metalua: fails on string with escape sequence '\/'. The Reference Manual --- doesn't say this sequence is valid though. - ---FIX:Metalua: In `local --[[x]] function --[[y]] f() end`, --- 'x' comment omitted from AST. - ---FIX:Metalua: `do --[[x]] end` doesn't generate comments in AST. --- `if x then --[[x]] end` and `while 1 do --[[x]] end` generates --- comments in first/last of block - ---FIX:Metalua: `--[[x]] f() --[[y]]` returns lineinfo around `f()`. --- `--[[x]] --[[y]]` returns lineinfo around everything. - ---FIX:Metalua: `while 1 do --[[x]] --[[y]] end` returns first > last --- lineinfo for contained block - ---FIX:Metalua: search for "PATCHED:LuaInspect" in the metalualib folder. - ---FIX?:Metalua: loadstring parses "--x" but metalua omits the comment in the AST - ---FIX?:Metalua: `local x` is generating `Local{{`Id{x}}, {}}`, which --- has no lineinfo on {}. This is contrary to the Metalua --- spec: `Local{ {ident+} {expr+}? }. --- Other things like `self` also generate no lineinfo. --- The ast2.lineinfo above avoids this. - ---FIX:Metalua: Metalua shouldn't overwrite ipairs/pairs. Note: Metalua version --- doesn't set errorlevel correctly. - ---Q:Metalua: Why does `return --[[y]] z --[[x]]` have --- lineinfo.first.comments, lineinfo.last.comments, --- plus lineinfo.comments (which is the same as lineinfo.first.comments) ? - ---CAUTION:Metalua: `do f() end` returns lineinfo around `do f() end`, while --- `while 1 do f() end` returns lineinfo around `f()` for inner block. - ---CAUTION:Metalua: The lineinfo on Metalua comments is inconsistent with other --- nodes - ---CAUTION:Metalua: lineinfo of table in `f{}` is [3,2], of `f{ x,y }` it's [4,6]. --- This is inconsistent with `x={}` which is [3,4] and `f""` which is [1,2] --- for the string. - ---CAUTION:Metalua: only the `function()` form of `Function includes `function` --- in lineinfo. 'function' is part of `Localrec and `Set in syntactic sugar form. - - ---[=[TESTSUITE --- test longest_prefix/longest_postfix -local function pr(text1, text2) - local lastv - local function same(v) - assert(not lastv or v == lastv); lastv = v; return v - end - local function test1(text1, text2) -- test prefix/postfix - same(longest_prefix(text1, text2)) - same(longest_postfix(text1:reverse(), text2:reverse())) - end - local function test2(text1, text2) -- test swap - test1(text1, text2) - test1(text2, text1) - end - for _,extra in ipairs{"", "x", "xy", "xyz"} do -- test extra chars - test2(text1, text2..extra) - test2(text2, text1..extra) - end - return lastv -end -check('==', pr("",""), 0) -check('==', pr("a",""), 0) -check('==', pr("a","a"), 1) -check('==', pr("ab",""), 0) -check('==', pr("ab","a"), 1) -check('==', pr("ab","ab"), 2) -check('==', pr("abcdefg","abcdefgh"), 7) ---]=] - ---[=[TESTSUITE -print 'DONE' ---]=] - - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/compat_env.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/compat_env.lua deleted file mode 100644 index 326b3b4..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/compat_env.lua +++ /dev/null @@ -1,390 +0,0 @@ ---[[ - - compat_env v$(_VERSION) - Lua 5.1/5.2 environment compatibility functions - -SYNOPSIS - - -- Get load/loadfile compatibility functions only if using 5.1. - local CL = pcall(load, '') and _G or require 'compat_env' - local load = CL.load - local loadfile = CL.loadfile - - -- The following now works in both Lua 5.1 and 5.2: - assert(load('return 2*pi', nil, 't', {pi=math.pi}))() - assert(loadfile('ex.lua', 't', {print=print}))() - - -- Get getfenv/setfenv compatibility functions only if using 5.2. - local getfenv = _G.getfenv or require 'compat_env'.getfenv - local setfenv = _G.setfenv or require 'compat_env'.setfenv - local function f() return x end - setfenv(f, {x=2}) - print(x, getfenv(f).x) --> 2, 2 - -DESCRIPTION - - This module provides Lua 5.1/5.2 environment related compatibility functions. - This includes implementations of Lua 5.2 style `load` and `loadfile` - for use in Lua 5.1. It also includes Lua 5.1 style `getfenv` and `setfenv` - for use in Lua 5.2. - -API - - local CL = require 'compat_env' - - CL.load (ld [, source [, mode [, env] ] ]) --> f [, err] - - This behaves the same as the Lua 5.2 `load` in both - Lua 5.1 and 5.2. - http://www.lua.org/manual/5.2/manual.html#pdf-load - - CL.loadfile ([filename [, mode [, env] ] ]) --> f [, err] - - This behaves the same as the Lua 5.2 `loadfile` in both - Lua 5.1 and 5.2. - http://www.lua.org/manual/5.2/manual.html#pdf-loadfile - - CL.getfenv ([f]) --> t - - This is identical to the Lua 5.1 `getfenv` in Lua 5.1. - This behaves similar to the Lua 5.1 `getfenv` in Lua 5.2. - When a global environment is to be returned, or when `f` is a - C function, this returns `_G` since Lua 5.2 doesn't have - (thread) global and C function environments. This will also - return `_G` if the Lua function `f` lacks an `_ENV` - upvalue, but it will raise an error if uncertain due to lack of - debug info. It is not normally considered good design to use - this function; when possible, use `load` or `loadfile` instead. - http://www.lua.org/manual/5.1/manual.html#pdf-getfenv - - CL.setfenv (f, t) - - This is identical to the Lua 5.1 `setfenv` in Lua 5.1. - This behaves similar to the Lua 5.1 `setfenv` in Lua 5.2. - This will do nothing if `f` is a Lua function that - lacks an `_ENV` upvalue, but it will raise an error if uncertain - due to lack of debug info. See also Design Notes below. - It is not normally considered good design to use - this function; when possible, use `load` or `loadfile` instead. - http://www.lua.org/manual/5.1/manual.html#pdf-setfenv - -DESIGN NOTES - - This module intends to provide robust and fairly complete reimplementations - of the environment related Lua 5.1 and Lua 5.2 functions. - No effort is made, however, to simulate rare or difficult to simulate features, - such as thread environments, although this is liable to change in the future. - Such 5.1 capabilities are discouraged and ideally - removed from 5.1 code, thereby allowing your code to work in both 5.1 and 5.2. - - In Lua 5.2, a `setfenv(f, {})`, where `f` lacks any upvalues, will be silently - ignored since there is no `_ENV` in this function to write to, and the - environment will have no effect inside the function anyway. However, - this does mean that `getfenv(setfenv(f, t))` does not necessarily equal `t`, - which is incompatible with 5.1 code (a possible workaround would be [1]). - If `setfenv(f, {})` has an upvalue but no debug info, then this will raise - an error to prevent inadvertently executing potentially untrusted code in the - global environment. - - It is not normally considered good design to use `setfenv` and `getfenv` - (one reason they were removed in 5.2). When possible, consider replacing - these with `load` or `loadfile`, which are more restrictive and have native - implementations in 5.2. - - This module might be merged into a more general Lua 5.1/5.2 compatibility - library (e.g. a full reimplementation of Lua 5.2 `_G`). However, - `load/loadfile/getfenv/setfenv` perhaps are among the more cumbersome - functions not to have. - -INSTALLATION - - Download compat_env.lua: - - wget https://raw.github.com/gist/1654007/compat_env.lua - - Copy compat_env.lua into your LUA_PATH. - - Alternately, unpack, test, and install into LuaRocks: - - wget https://raw.github.com/gist/1422205/sourceunpack.lua - lua sourceunpack.lua compat_env.lua - (cd out && luarocks make) - -Related work - - http://lua-users.org/wiki/LuaVersionCompatibility - https://github.com/stevedonovan/Penlight/blob/master/lua/pl/utils.lua - - penlight implementations of getfenv/setfenv - http://lua-users.org/lists/lua-l/2010-06/msg00313.html - - initial getfenv/setfenv implementation - -References - - [1] http://lua-users.org/lists/lua-l/2010-06/msg00315.html - -Copyright - -(c) 2012 David Manura. Licensed under the same terms as Lua 5.1/5.2 (MIT license). - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---]]--------------------------------------------------------------------- - -local M = {_TYPE='module', _NAME='compat_env', _VERSION='0.2.20120124'} - -local function check_chunk_type(s, mode) - local nmode = mode or 'bt' - local is_binary = s and #s > 0 and s:byte(1) == 27 - if is_binary and not nmode:match'b' then - return nil, ("attempt to load a binary chunk (mode is '%s')"):format(mode) - elseif not is_binary and not nmode:match't' then - return nil, ("attempt to load a text chunk (mode is '%s')"):format(mode) - end - return true -end - -local IS_52_LOAD = pcall(load, '') -if IS_52_LOAD then - M.load = _G.load - M.loadfile = _G.loadfile -else - -- 5.2 style `load` implemented in 5.1 - function M.load(ld, source, mode, env) - local f - if type(ld) == 'string' then - local s = ld - local ok, err = check_chunk_type(s, mode); if not ok then return ok, err end - local err; f, err = loadstring(s, source); if not f then return f, err end - elseif type(ld) == 'function' then - local ld2 = ld - if (mode or 'bt') ~= 'bt' then - local first = ld() - local ok, err = check_chunk_type(first, mode); if not ok then return ok, err end - ld2 = function() - if first then - local chunk=first; first=nil; return chunk - else return ld() end - end - end - local err; f, err = load(ld2, source); if not f then return f, err end - else - error(("bad argument #1 to 'load' (function expected, got %s)"):format(type(ld)), 2) - end - if env then setfenv(f, env) end - return f - end - - -- 5.2 style `loadfile` implemented in 5.1 - function M.loadfile(filename, mode, env) - if (mode or 'bt') ~= 'bt' then - local ioerr - local fh, err = io.open(filename, 'rb'); if not fh then return fh, err end - local function ld() local chunk; chunk,ioerr = fh:read(4096); return chunk end - local f, err = M.load(ld, filename and '@'..filename, mode, env) - fh:close() - if not f then return f, err end - if ioerr then return nil, ioerr end - return f - else - local f, err = loadfile(filename); if not f then return f, err end - if env then setfenv(f, env) end - return f - end - end -end - -if _G.setfenv then -- Lua 5.1 - M.setfenv = _G.setfenv - M.getfenv = _G.getfenv -else -- >= Lua 5.2 - -- helper function for `getfenv`/`setfenv` - local function envlookup(f) - local name, val - local up = 0 - local unknown - repeat - up=up+1; name, val = debug.getupvalue(f, up) - if name == '' then unknown = true end - until name == '_ENV' or name == nil - if name ~= '_ENV' then - up = nil - if unknown then error("upvalues not readable in Lua 5.2 when debug info missing", 3) end - end - return (name == '_ENV') and up, val, unknown - end - - -- helper function for `getfenv`/`setfenv` - local function envhelper(f, name) - if type(f) == 'number' then - if f < 0 then - error(("bad argument #1 to '%s' (level must be non-negative)"):format(name), 3) - elseif f < 1 then - error("thread environments unsupported in Lua 5.2", 3) --[*] - end - f = debug.getinfo(f+2, 'f').func - elseif type(f) ~= 'function' then - error(("bad argument #1 to '%s' (number expected, got %s)"):format(type(name, f)), 2) - end - return f - end - -- [*] might simulate with table keyed by coroutine.running() - - -- 5.1 style `setfenv` implemented in 5.2 - function M.setfenv(f, t) - local f = envhelper(f, 'setfenv') - local up, val, unknown = envlookup(f) - if up then - debug.upvaluejoin(f, up, function() return up end, 1) -- unique upvalue [*] - debug.setupvalue(f, up, t) - else - local what = debug.getinfo(f, 'S').what - if what ~= 'Lua' and what ~= 'main' then -- not Lua func - error("'setfenv' cannot change environment of given object", 2) - end -- else ignore no _ENV upvalue (warning: incompatible with 5.1) - end - end - -- [*] http://lua-users.org/lists/lua-l/2010-06/msg00313.html - - -- 5.1 style `getfenv` implemented in 5.2 - function M.getfenv(f) - if f == 0 or f == nil then return _G end -- simulated behavior - local f = envhelper(f, 'setfenv') - local up, val = envlookup(f) - if not up then return _G end -- simulated behavior [**] - return val - end - -- [**] possible reasons: no _ENV upvalue, C function -end - - -return M - ---[[ FILE rockspec.in - -package = 'compat_env' -version = '$(_VERSION)-1' -source = { - url = 'https://raw.github.com/gist/1654007/$(GITID)/compat_env.lua', - --url = 'https://raw.github.com/gist/1654007/compat_env.lua', -- latest raw - --url = 'https://gist.github.com/gists/1654007/download', - md5 = '$(MD5)' -} -description = { - summary = 'Lua 5.1/5.2 environment compatibility functions', - detailed = [=[ - Provides Lua 5.1/5.2 environment related compatibility functions. - This includes implementations of Lua 5.2 style `load` and `loadfile` - for use in Lua 5.1. It also includes Lua 5.1 style `getfenv` and `setfenv` - for use in Lua 5.2. - ]=], - license = 'MIT/X11', - homepage = 'https://gist.github.com/1654007', - maintainer = 'David Manura' -} -dependencies = {} -- Lua 5.1 or 5.2 -build = { - type = 'builtin', - modules = { - ['compat_env'] = 'compat_env.lua' - } -} - ---]]--------------------------------------------------------------------- - ---[[ FILE test.lua - --- test.lua - test suite for compat_env module. - -local CL = require 'compat_env' -local load = CL.load -local loadfile = CL.loadfile -local setfenv = CL.setfenv -local getfenv = CL.getfenv - -local function checkeq(a, b, e) - if a ~= b then error( - 'not equal ['..tostring(a)..'] ['..tostring(b)..'] ['..tostring(e)..']') - end -end -local function checkerr(pat, ok, err) - assert(not ok, 'checkerr') - assert(type(err) == 'string' and err:match(pat), err) -end - --- test `load` -checkeq(load('return 2')(), 2) -checkerr('expected near', load'return 2 2') -checkerr('text chunk', load('return 2', nil, 'b')) -checkerr('text chunk', load('', nil, 'b')) -checkerr('binary chunk', load('\027', nil, 't')) -checkeq(load('return 2*x',nil,'bt',{x=5})(), 10) -checkeq(debug.getinfo(load('')).source, '') -checkeq(debug.getinfo(load('', 'foo')).source, 'foo') - --- test `loadfile` -local fh = assert(io.open('tmp.lua', 'wb')) -fh:write('return (...) or x') -fh:close() -checkeq(loadfile('tmp.lua')(2), 2) -checkeq(loadfile('tmp.lua', 't')(2), 2) -checkerr('text chunk', loadfile('tmp.lua', 'b')) -checkeq(loadfile('tmp.lua', nil, {x=3})(), 3) -checkeq(debug.getinfo(loadfile('tmp.lua')).source, '@tmp.lua') -checkeq(debug.getinfo(loadfile('tmp.lua', 't', {})).source, '@tmp.lua') -os.remove'tmp.lua' - --- test `setfenv`/`getfenv` -x = 5 -local a,b=true; local function f(c) if a then return x,b,c end end -setfenv(f, {x=3}) -checkeq(f(), 3) -checkeq(getfenv(f).x, 3) -checkerr('cannot change', pcall(setfenv, string.len, {})) -- C function -checkeq(getfenv(string.len), _G) -- C function -local function g() - setfenv(1, {x=4}) - checkeq(getfenv(1).x, 4) - return x -end -checkeq(g(), 4) -- numeric level -if _G._VERSION ~= 'Lua 5.1' then - checkerr('unsupported', pcall(setfenv, 0, {})) -end -checkeq(getfenv(0), _G) -checkeq(getfenv(), _G) -- no arg -checkeq(x, 5) -- main unaltered -setfenv(function()end, {}) -- no upvalues, ignore -checkeq(getfenv(function()end), _G) -- no upvaluse -if _G._VERSION ~= 'Lua 5.1' then - checkeq(getfenv(setfenv(function()end, {})), _G) -- warning: incompatible with 5.1 -end -x = nil - -print 'OK' - ---]]--------------------------------------------------------------------- - ---[[ FILE CHANGES.txt -0.2.20120124 - Renamed module to compat_env (from compat_load) - Add getfenv/setfenv functions - -0.1.20120121 - Initial public release ---]] - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/dump.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/dump.lua deleted file mode 100644 index 6a6e980..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/dump.lua +++ /dev/null @@ -1,90 +0,0 @@ --- Recursive object dumper, for debugging. --- (c) 2010 David Manura, MIT License. - -local M = {} - --- My own object dumper. --- Intended for debugging, not serialization, with compact formatting. --- Robust against recursion. --- Renders Metalua table tag fields specially {tag=X, ...} --> "`X{...}". --- On first call, only pass parameter o. --- CATEGORY: AST debug -local ignore_keys_ = {lineinfo=true} -local norecurse_keys_ = {parent=true, ast=true} -local function dumpstring_key_(k, isseen, newindent) - local ks = type(k) == 'string' and k:match'^[%a_][%w_]*$' and k or - '[' .. M.dumpstring(k, isseen, newindent) .. ']' - return ks -end -local function sort_keys_(a, b) - if type(a) == 'number' and type(b) == 'number' then - return a < b - elseif type(a) == 'number' then - return false - elseif type(b) == 'number' then - return true - elseif type(a) == 'string' and type(b) == 'string' then - return a < b - else - return tostring(a) < tostring(b) -- arbitrary - end -end -function M.dumpstring(o, isseen, indent, key) - isseen = isseen or {} - indent = indent or '' - - if type(o) == 'table' then - if isseen[o] or norecurse_keys_[key] then - return (type(o.tag) == 'string' and '`' .. o.tag .. ':' or '') .. tostring(o) - else isseen[o] = true end -- avoid recursion - - local used = {} - - local tag = o.tag - local s = '{' - if type(o.tag) == 'string' then - s = '`' .. tag .. s; used['tag'] = true - end - local newindent = indent .. ' ' - - local ks = {}; for k in pairs(o) do ks[#ks+1] = k end - table.sort(ks, sort_keys_) - --for i,k in ipairs(ks) do print ('keys', k) end - - local forcenummultiline - for k in pairs(o) do - if type(k) == 'number' and type(o[k]) == 'table' then forcenummultiline = true end - end - - -- inline elements - for _,k in ipairs(ks) do - if used[k] then -- skip - elseif ignore_keys_[k] then used[k] = true - elseif (type(k) ~= 'number' or not forcenummultiline) and - type(k) ~= 'table' and (type(o[k]) ~= 'table' or norecurse_keys_[k]) - then - s = s .. dumpstring_key_(k, isseen, newindent) .. '=' .. M.dumpstring(o[k], isseen, newindent, k) .. ', ' - used[k] = true - end - end - - -- elements on separate lines - local done - for _,k in ipairs(ks) do - if not used[k] then - if not done then s = s .. '\n'; done = true end - s = s .. newindent .. dumpstring_key_(k, isseen) .. '=' .. M.dumpstring(o[k], isseen, newindent, k) .. ',\n' - end - end - s = s:gsub(',(%s*)$', '%1') - s = s .. (done and indent or '') .. '}' - return s - elseif type(o) == 'string' then - return string.format('%q', o) - else - return tostring(o) - end -end - -return M - diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/globals.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/globals.lua deleted file mode 100644 index 0730909..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/globals.lua +++ /dev/null @@ -1,222 +0,0 @@ --- LuaInspect.globals - identifier scope analysis --- Locates locals, globals, and their definitions. --- --- (c) D.Manura, 2008-2010, MIT license. - --- based on http://lua-users.org/wiki/DetectingUndefinedVariables - -local M = {} - ---! require 'luainspect.typecheck' (context) - -local LA = require "luainspect.ast" - -local function definelocal(scope, name, ast) - if scope[name] then - scope[name].localmasked = true - ast.localmasking = scope[name] - end - scope[name] = ast - if name == '_' then ast.isignore = true end -end - --- Resolves scoping and usages of variable in AST. --- Data Notes: --- ast.localdefinition refers to lexically scoped definition of `Id node `ast`. --- If ast.localdefinition == ast then ast is a "lexical definition". --- If ast.localdefinition == nil, then variable is global. --- ast.functionlevel is the number of functions the AST is contained in. --- ast.functionlevel is defined iff ast is a lexical definition. --- ast.isparam is true iff ast is a lexical definition and a function parameter. --- ast.isset is true iff ast is a lexical definition and exists an assignment on it. --- ast.isused is true iff ast is a lexical definition and has been referred to. --- ast.isignore is true if local variable should be ignored (e.g. typically "_") --- ast.localmasking - for a lexical definition, this is set to the lexical definition --- this is masking (i.e. same name). nil if not masking. --- ast.localmasked - true iff lexical definition masked by another lexical definition. --- ast.isfield is true iff `String node ast is used for field access on object, --- e.g. x.y or x['y'].z --- ast.previous - For `Index{o,s} or `Invoke{o,s,...}, s.previous == o -local function traverse(ast, scope, globals, level, functionlevel) - scope = scope or {} - - local blockrecurse - ast.level = level - - -- operations on walking down the AST - if ast.tag == 'Local' then - blockrecurse = 1 - -- note: apply new scope after processing values - elseif ast.tag == 'Localrec' then - local namelist_ast, valuelist_ast = ast[1], ast[2] - for _,value_ast in ipairs(namelist_ast) do - assert(value_ast.tag == 'Id') - local name = value_ast[1] - local parentscope = getmetatable(scope).__index - definelocal(parentscope, name, value_ast) - value_ast.localdefinition = value_ast - value_ast.functionlevel = functionlevel - value_ast.level = level+1 - end - blockrecurse = 1 - elseif ast.tag == 'Id' then - local name = ast[1] - if scope[name] then - ast.localdefinition = scope[name] - ast.functionlevel = functionlevel - scope[name].isused = true - else -- global, do nothing - end - elseif ast.tag == 'Function' then - local paramlist_ast, body_ast = ast[1], ast[2] - functionlevel = functionlevel + 1 - for _,param_ast in ipairs(paramlist_ast) do - local name = param_ast[1] - assert(param_ast.tag == 'Id' or param_ast.tag == 'Dots') - if param_ast.tag == 'Id' then - definelocal(scope, name, param_ast) - param_ast.localdefinition = param_ast - param_ast.functionlevel = functionlevel - param_ast.isparam = true - end - param_ast.level = level+1 - end - blockrecurse = 1 - elseif ast.tag == 'Set' then - local reflist_ast, valuelist_ast = ast[1], ast[2] - for _,ref_ast in ipairs(reflist_ast) do - if ref_ast.tag == 'Id' then - local name = ref_ast[1] - if scope[name] then - scope[name].isset = true - else - if not globals[name] then - globals[name] = {set=ref_ast} - end - end - end - ref_ast.level = level+1 - end - --ENHANCE? We could differentiate assignments to x (which indicates that - -- x is not const) and assignments to a member of x (which indicates that - -- x is not a pointer to const) and assignments to any nested member of x - -- (which indicates that x it not a transitive const). - elseif ast.tag == 'Fornum' then - blockrecurse = 1 - elseif ast.tag == 'Forin' then - blockrecurse = 1 - end - - -- recurse (depth-first search down the AST) - if ast.tag == 'Repeat' then - local block_ast, cond_ast = ast[1], ast[2] - local scope = scope - for _,stat_ast in ipairs(block_ast) do - scope = setmetatable({}, {__index = scope}) - traverse(stat_ast, scope, globals, level+1, functionlevel) - end - scope = setmetatable({}, {__index = scope}) - traverse(cond_ast, scope, globals, level+1, functionlevel) - elseif ast.tag == 'Fornum' then - local name_ast, block_ast = ast[1], ast[#ast] - -- eval value list in current scope - for i=2, #ast-1 do traverse(ast[i], scope, globals, level+1, functionlevel) end - -- eval body in next scope - local name = name_ast[1] - definelocal(scope, name, name_ast) - name_ast.localdefinition = name_ast - name_ast.functionlevel = functionlevel - traverse(block_ast, scope, globals, level+1, functionlevel) - elseif ast.tag == 'Forin' then - local namelist_ast, vallist_ast, block_ast = ast[1], ast[2], ast[3] - -- eval value list in current scope - traverse(vallist_ast, scope, globals, level+1, functionlevel) - -- eval body in next scope - for _,name_ast in ipairs(namelist_ast) do - local name = name_ast[1] - definelocal(scope, name, name_ast) - name_ast.localdefinition = name_ast - name_ast.functionlevel = functionlevel - name_ast.level = level+1 - end - traverse(block_ast, scope, globals, level+1, functionlevel) - else -- normal - for i,v in ipairs(ast) do - if i ~= blockrecurse and type(v) == 'table' then - local scope = setmetatable({}, {__index = scope}) - traverse(v, scope, globals, level+1, functionlevel) - end - end - end - - -- operations on walking up the AST - if ast.tag == 'Local' then - -- Unlike Localrec, variables come into scope after evaluating values. - local namelist_ast, valuelist_ast = ast[1], ast[2] - for _,name_ast in ipairs(namelist_ast) do - assert(name_ast.tag == 'Id') - local name = name_ast[1] - local parentscope = getmetatable(scope).__index - definelocal(parentscope, name, name_ast) - name_ast.localdefinition = name_ast - name_ast.functionlevel = functionlevel - name_ast.level = level+1 - end - elseif ast.tag == 'Index' then - if ast[2].tag == 'String' then - ast[2].isfield = true - ast[2].previous = ast[1] - end - elseif ast.tag == 'Invoke' then - assert(ast[2].tag == 'String') - ast[2].isfield = true - ast[2].previous = ast[1] - end -end - -function M.globals(ast) - -- Default list of defined variables. - local scope = setmetatable({}, {}) - local globals = {} - traverse(ast, scope, globals, 1, 1) -- Start check. - - return globals -end - - --- Gets locals in scope of statement of block ast. If isafter is true and ast is statement, --- uses scope just after statement ast. --- Assumes 'parent' attributes on ast are marked. --- Returns table mapping name -> AST local definition. -function M.variables_in_scope(ast, isafter) - local scope = {} - local cast = ast - while cast.parent do - local midx = LA.ast_idx(cast.parent, cast) - for idx=1,midx do - local bast = cast.parent[idx] - if bast.tag == 'Localrec' or bast.tag == 'Local' and (idx < midx or isafter) then - local names_ast = bast[1] - for bidx=1,#names_ast do - local name_ast = names_ast[bidx] - local name = name_ast[1] - scope[name] = name_ast - end - elseif cast ~= ast and (bast.tag == 'For' or bast.tag == 'Forin' or bast.tag == 'Function') then - local names_ast = bast[1] - for bidx=1,#names_ast do - local name_ast = names_ast[bidx] - if name_ast.tag == 'Id' then --Q: or maybe `Dots should be included - local name = name_ast[1] - scope[name] = name_ast - end - end - end - end - cast = cast.parent - end - return scope -end - - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/init.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/init.lua deleted file mode 100644 index bab48fa..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/init.lua +++ /dev/null @@ -1,1454 +0,0 @@ --- luainspect.init - core LuaInspect source analysis. --- --- This module is a bit more high level than luainspect.ast. It deals more with --- interpretation/inference of semantics of an AST. It also uses luainspect.globals, --- which does the basic semantic interpretation of globals/locals. --- --- (c) 2010 David Manura, MIT License. - -local M = {} - --- This is the API version. It is an ISO8601 date expressed as a fraction. -M.APIVERSION = 0.20100805 - -local LA = require "luainspect.ast" -local LD = require "luainspect.dump" -local LG = require "luainspect.globals" -local LS = require "luainspect.signatures" -local T = require "luainspect.types" -local COMPAT = require "luainspect.compat_env" - ---! require 'luainspect.typecheck' (context) - -local ENABLE_RETURN_ANALYSIS = true -local DETECT_DEADCODE = false -- may require more validation (false positives) - - --- Functional forms of Lua operators. --- Note: variable names like _1 are intentional. These affect debug info and --- will display in any error messages. -local ops = {} -ops['add'] = function(_1,_2) return _1+_2 end -ops['sub'] = function(_1,_2) return _1-_2 end -ops['mul'] = function(_1,_2) return _1*_2 end -ops['div'] = function(_1,_2) return _1/_2 end -ops['mod'] = function(_1,_2) return _1%_2 end -ops['pow'] = function(_1,_2) return _1^_2 end -ops['concat'] = function(_1,_2) return _1.._2 end -ops['eq'] = function(_1,_2) return _1==_2 end -ops['lt'] = function(_1,_2) return _1<_2 end -ops['le'] = function(_1,_2) return _1<=_2 end -ops['and'] = function(_1,_2) return _1 and _2 end -ops['or'] = function(_1,_2) return _1 or _2 end -ops['not'] = function(_1) return not _1 end -ops['len'] = function(_1) return #_1 end -ops['unm'] = function(_1) return -_1 end - - --- Performs binary operation. Supports types. -local function dobinop(opid, a, b) - if (a == T.number or b == T.number) and - (a == T.number or type(a) == 'number' ) and - (b == T.number or type(b) == 'number' ) - then - if opid == 'eq' or opid == 'lt' or opid == 'le' then - return T.boolean - elseif opid == 'concat' then - return T.string - else - return T.number - end - elseif (a == T.string or b == T.string) and - (a == T.string or type(a) == 'string' ) and - (b == T.string or type(b) == 'string' ) - then - if opid == 'concat' or opid == 'and' or opid == 'or' then - return T.string - elseif opid == 'eq' or opid == 'lt' or opid == 'le' then - return T.boolean - else - return T.number - end - elseif (a == T.boolean or b == T.boolean) and - (a == T.boolean or type(a) == 'boolean' ) and - (b == T.boolean or type(b) == 'boolean' ) - then - if opid == 'eq' or opid == 'and' or opid == 'or' then - return T.boolean - else - error('invalid operation on booleans: ' .. opid, 0) - end - elseif T.istype[a] or T.istype[b] then - return T.universal - else - return ops[opid](a, b) - end -end - - --- Performs unary operation. Supports types. -local function dounop(opid, a) - if opid == 'not' then - if T.istype[a] then - return T.boolean - else - return ops[opid](a) - end - elseif a == T.number then - if opid == 'unm' then - return T.number - else -- 'len' - error('invalid operation on number: ' .. opid, 0) - end - elseif a == T.string then - return T.number - elseif a == T.boolean then - error('invalid operation on boolean: ' .. opid, 0) - elseif T.istype[a] then - return nil, 'unknown' - else - return ops[opid](a) - end -end - --- Like info in debug.getinfo but inferred by static analysis. --- object -> {fpos=fpos, source="@" .. source, fast=ast, tokenlist=tokenlist} --- Careful: value may reference key (affects pre-5.2 which lacks emphemerons). --- See also ast.nocollect. -M.debuginfo = setmetatable({}, {__mode='v'}) - --- Modules loaded via require_inspect. --- module name string -> {return value, AST node} --- note: AST node is maintained to prevent nocollect fields in ast being collected. --- note: not a weak table. -M.package_loaded = {} - --- Stringifies interpreted value for debugging. --- CATEGORY: debug -local function debugvalue(ast) - local s - if ast then - s = ast.value ~= T.universal and 'known:' .. tostring(ast.value) or 'unknown' - else - s = '?' - end - return s -end - - --- Reads contents of text file in path, in binary mode. --- On error, returns nil and error message. -local function readfile(path) - local fh, err = io.open(path, 'rb') - if fh then - local data; data, err = fh:read'*a' - if data then return data end - end - return nil, err -end - --- Similar to string.gsub but with plain replacement (similar to option in string.match) --- http://lua-users.org/lists/lua-l/2002-04/msg00118.html --- CATEGORY: utility/string -local function plain_gsub(s, pattern, repl) - repl = repl:gsub('(%%)', '%%%%') - return s:gsub(pattern, repl) -end - --- Infer name of variable or literal that AST node represents. --- This is for debugging messages. -local function infer_name(ast) - if ast == nil then return nil - elseif ast.tag == 'Id' then return "'"..ast[1].."'" - elseif ast.tag == 'Number' then return 'number' - elseif ast.tag == 'String' then return 'string' - elseif ast.tag == 'True' then return 'true' - elseif ast.tag == 'False' then return 'false' - elseif ast.tag == 'Nil' then return 'nil' - else return nil end -end - ---[[ - This is like `pcall` but any error string returned does not contain the - "chunknamem:currentline: " prefix (based on luaL_where) if the error occurred - in the current file. This avoids error messages in user code (f) - being reported as being inside this module if this module calls user code. - Also, local variable names _1, _2, etc. in error message are replaced with names - inferred (if any) from corresponding AST nodes in list `asts` (note: nil's in asts skip replacement). ---]] -local _prefix -local _clean -local function pzcall(f, asts, ...) - _prefix = _prefix or select(2, pcall(function() error'' end)):gsub(':%d+: *$', '') -- note: specific to current file. - _clean = _clean or function(asts, ok, ...) - if ok then return true, ... - else - local err = ... - if type(err) == 'string' then - if err:sub(1,#_prefix) == _prefix then - local more = err:match('^:%d+: *(.*)', #_prefix+1) - if more then - err = more - err = err:gsub([[local '_(%d+)']], function(name) return infer_name(asts[tonumber(name)]) end) - end - end - end - return ok, err - end - end - return _clean(asts, pcall(f, ...)) -end - --- Loads source code of given module name. --- Returns code followed by path. --- note: will also search in the directory `spath` and its parents. --- This should preferrably be an absolute path or it might not work correctly. --- It must be slash terminated. --- CATEGORY: utility/package -local function load_module_source(name, spath) - -- Append parent directories to list of paths to search. - local package_path = package.path - local ppath = spath - repeat - package_path = package_path .. ';' .. ppath .. '?.lua;' .. ppath .. '?/init.lua' - local nsub - ppath, nsub = ppath:gsub('[^\\/]+[\\/]$', '') - until nsub == 0 - - for spec in package_path:gmatch'[^;]+' do - local testpath = plain_gsub(spec, '%?', (name:gsub('%.', '/'))) - local src, err_ = readfile(testpath) - if src then return src, testpath end - end - return nil -end - - --- Clears global state. --- This includes cached inspected modules. -function M.clear_cache() - for k,v in pairs(M.package_loaded) do - M.package_loaded[k] = nil - end -end - - --- Gets all keywords related to AST `ast`, where `top_ast` is the root of `ast` --- and `src` is source code of `top_ast` --- Related keywords are defined as all keywords directly associated with block containing node --- `ast`. Furthermore, break statements are related to containing loop statements, --- and return statements are related to containing function statement (if any). --- function declaration syntactic sugar is handled specially too to ensure the 'function' keyword --- is highlighted even though it may be outside of the `Function AST. --- --- Returns token list or nil if not applicable. Returned `ast` is AST containing related keywords. --- CATEGORY: keyword comprehension -local iskeystat = {Do=true, While=true, Repeat=true, If=true, Fornum=true, Forin=true, - Local=true, Localrec=true, Return=true, Break=true, Function=true, - Set=true -- note: Set for `function name` -} -local isloop = {While=true, Repeat=true, Fornum=true, Forin=true} -local isblock = {Do=true, While=true, Repeat=true, If=true, Fornum=true, Forin=true, Function=true} -function M.related_keywords(ast, top_ast, tokenlist, src) - -- Expand or contract AST for certain contained statements. - local more - if ast.tag == 'Return' then - -- if `return` selected, that consider containing function selected (if any) - if not ast.parent then LA.mark_parents(top_ast) end - local ancestor_ast = ast.parent - while ancestor_ast ~= nil and ancestor_ast.tag ~= 'Function' do - ancestor_ast = ancestor_ast.parent - end - if ancestor_ast then ast = ancestor_ast end -- but only change if exists - elseif ast.tag == 'Break' then - -- if `break` selected, that consider containing loop selected - if not ast.parent then LA.mark_parents(top_ast) end - local ancestor_ast = ast.parent - while ancestor_ast ~= nil and not isloop[ancestor_ast.tag] do - ancestor_ast = ancestor_ast.parent - end - ast = ancestor_ast - elseif ast.tag == 'Set' then - local val1_ast = ast[2][1] - if val1_ast.tag == 'Function' then - local token = tokenlist[LA.ast_idx_range_in_tokenlist(tokenlist, ast)] - if token.tag == 'Keyword' and token[1] == 'function' then -- function with syntactic sugar `function f` - ast = ast[2][1] -- select `Function node - else - more = true - end - else - more = true - end - elseif ast.tag == 'Localrec' and ast[2][1].tag == 'Function' then - -- if `local function f` selected, which becomes a `Localrec, consider `Function node. - ast = ast[2][1] - --IMPROVE: only contract ast if `function` part of `local function` is selected. - else - more = true - end - if more then -- not yet handled - -- Consider containing block. - if not ast.parent then LA.mark_parents(top_ast) end - local ancestor_ast = ast - while ancestor_ast ~= top_ast and not isblock[ancestor_ast.tag] do - ancestor_ast = ancestor_ast.parent - end - ast = ancestor_ast - end - - -- keywords in statement/block. - if iskeystat[ast.tag] then - local keywords = {} - for i=1,#tokenlist do - local token = tokenlist[i] - if token.ast == ast and token.tag == 'Keyword' then - keywords[#keywords+1] = token - end - end - - -- Expand keywords for certaining statements. - if ast.tag == 'Function' then - -- if `Function, also select 'function' and 'return' keywords - local function f(ast) - for _,cast in ipairs(ast) do - if type(cast) == 'table' then - if cast.tag == 'Return' then - local token = tokenlist[LA.ast_idx_range_in_tokenlist(tokenlist, cast)] - keywords[#keywords+1] = token - elseif cast.tag ~= 'Function' then f(cast) end - end - end - end - f(ast) - if not ast.parent then LA.mark_parents(top_ast) end - local grand_ast = ast.parent.parent - if grand_ast.tag == 'Set' then - local token = tokenlist[LA.ast_idx_range_in_tokenlist(tokenlist, grand_ast)] - if token.tag == 'Keyword' and token[1] == 'function' then - keywords[#keywords+1] = token - end - elseif grand_ast.tag == 'Localrec' then - local tidx = LA.ast_idx_range_in_tokenlist(tokenlist, grand_ast) - repeat tidx = tidx + 1 until not tokenlist[tidx] or (tokenlist[tidx].tag == 'Keyword' and tokenlist[tidx][1] == 'function') - local token = tokenlist[tidx] - keywords[#keywords+1] = token - end - elseif isloop[ast.tag] then - -- if loop, also select 'break' keywords - local function f(ast) - for _,cast in ipairs(ast) do - if type(cast) == 'table' then - if cast.tag == 'Break' then - local tidx = LA.ast_idx_range_in_tokenlist(tokenlist, cast) - keywords[#keywords+1] = tokenlist[tidx] - elseif not isloop[cast.tag] then f(cast) end - end - end - end - f(ast) - end - - return keywords, ast - end - return nil, ast -end - - --- Mark tokenlist (top_ast/tokenlist/src) with keywordid AST attributes. --- All keywords related to each other have the same keyword ID integer. --- NOTE: This is not done/undone by inspect/uninspect. --- CATEGORY: keyword comprehension -function M.mark_related_keywords(top_ast, tokenlist, src) - local id = 0 - local idof = {} - for _, token in ipairs(tokenlist) do - if token.tag == 'Keyword' and not idof[token] then - id = id + 1 - local match_ast = - LA.smallest_ast_containing_range(top_ast, tokenlist, token.fpos, token.lpos) - local ktokenlist = M.related_keywords(match_ast, top_ast, tokenlist, src) - if ktokenlist then - for _, ktoken in ipairs(ktokenlist) do - ktoken.keywordid = id - idof[ktoken] = true - end - end - -- note: related_keywords may return a keyword set not containing given keyword. - end - end -end - - --- function for t[k] -local function tindex(_1, _2) return _1[_2] end - -local unescape = {['d'] = '.'} - - - --- Sets known value on ast to v if ast not pegged. --- CATEGORY: utility function for infer_values. -local function set_value(ast, v) - if not ast.isvaluepegged then - ast.value = v - end -end - - -local function known(o) - return not T.istype[o] -end -local function unknown(o) - return T.istype[o] -end - - --- CATEGORY: utility function for infer_values. -local function tastnewindex(t_ast, k_ast, v_ast) - if known(t_ast.value) and known(k_ast.value) and known(v_ast.value) then - local _1, _2, _3 = t_ast.value, k_ast.value, v_ast.value - if _1[_2] ~= nil and _3 ~= _1[_2] then -- multiple values - return T.universal - else - _1[_2] = _3 - return _3 - end - else - return T.universal - end -end - - --- Gets expected number of parameters for function (min, max) values. --- In case of vararg, max is unknown and set to nil. -local function function_param_range(ast) - local names_ast = ast[1] - if #names_ast >= 1 and names_ast[#names_ast].tag == 'Dots' then - return #names_ast-1, nil - else - return #names_ast, #names_ast - end -end - --- Gets number of arguments to function call: (min, max) range. --- In case of trailing vararg or function call, max is unknown and set to nil. -local function call_arg_range(ast) - if ast.tag == 'Invoke' then - if #ast >= 3 and - (ast[#ast].tag == 'Dots' or ast[#ast].tag == 'Call' or ast[#ast].tag == 'Invoke') - then - return #ast-2, nil - else - return #ast-1, #ast-1 - end - else - if #ast >= 2 and - (ast[#ast].tag == 'Dots' or ast[#ast].tag == 'Call' or ast[#ast].tag == 'Invoke') - then - return #ast-2, nil - else - return #ast-1, #ast-1 - end - end -end - - --- Reports warning. List of strings. -local function warn(report, ...) - report('warning: ' .. table.concat({...}, ' ')) -end - --- Reports status messages. List of strings. -local function status(report, ...) - report('status: ' .. table.concat({...}, ' ')) -end - --- unique value used to detect require loops (A require B require A) -local REQUIRE_SENTINEL = function() end - --- Gets single return value of chunk ast. Assumes ast is inspected. -local function chunk_return_value(ast) - local vinfo - if ENABLE_RETURN_ANALYSIS then - local info = M.debuginfo[ast.value] - local retvals = info and info.retvals - if retvals then - vinfo = retvals[1] - else - vinfo = T.universal - end - else - if ast[#ast] and ast[#ast].tag == 'Return' and ast[#ast][1] then - vinfo = ast[#ast][1] - else - vinfo = T.universal - end - end - return vinfo -end - --- Version of require that does source analysis (inspect) on module. -function M.require_inspect(name, report, spath) - local plinfo = M.package_loaded[name] - if plinfo == REQUIRE_SENTINEL then - warn(report, "loop in require when loading " .. name) - return nil - end - if plinfo then return plinfo[1] end - status(report, 'loading:' .. name) - M.package_loaded[name] = REQUIRE_SENTINEL -- avoid recursion on require loops - local msrc, mpath = load_module_source(name, spath) - local vinfo, mast - if msrc then - local err; mast, err = LA.ast_from_string(msrc, mpath) - if mast then - local mtokenlist = LA.ast_to_tokenlist(mast, msrc) - M.inspect(mast, mtokenlist, msrc, report) - vinfo = chunk_return_value(mast) - else - vinfo = T.error(err) - warn(report, err, " ", mpath) --Q:error printing good? - end - else - warn(report, 'module not found: ' .. name) - vinfo = T.error'module not found' --IMPROVE: include search paths? - end - M.package_loaded[name] = {vinfo, mast} - return vinfo, mast -end - - --- Marks AST node and all children as dead (ast.isdead). -local function mark_dead(ast) - LA.walk(ast, function(bast) bast.isdead = true end) -end - --- Gets list of `Return statement ASTs in `Function (or chunk) f_ast, not including --- return's in nested functions. Also returns boolean `has_implicit` indicating --- whether function may return by exiting the function without a return statement. --- Returns that are never exected are omitted (e.g. last return is omitted in --- `function f() if x then return 1 else return 2 end return 3 end`). --- Also marks AST nodes with ast.isdead (dead-code). -local function get_func_returns(f_ast) - local isalwaysreturn = {} - local returns = {} - local function f(ast, isdead) - for _,cast in ipairs(ast) do if type(cast) == 'table' then - if isdead then mark_dead(cast) end -- even if DETECT_DEADCODE disabled - if cast.tag ~= 'Function' and not isdead then -- skip nested functions - f(cast, isdead) -- depth-first traverse - end - if ast.tag ~= 'If' and isalwaysreturn[cast] then isdead = true end - -- subsequent statements in block never executed - end end - - -- Code on walking up AST: propagate children to parents - if ast.tag == 'Return' then - returns[#returns+1] = ast - isalwaysreturn[ast] = true - elseif ast.tag == 'If' then - if #ast%2 ~= 0 then -- has 'else' block - local isreturn = true - for i=2,#ast do - if (i%2==0 or i==#ast) and not isalwaysreturn[ast[i]] then isreturn = nil; break end - end - isalwaysreturn[ast] = isreturn - end - else -- note: iterates not just blocks, but should be ok - for i=1,#ast do - if isalwaysreturn[ast[i]] then - isalwaysreturn[ast] = true; break - end - end - end - end - f(f_ast, false) - local block_ast = f_ast.tag == 'Function' and f_ast[2] or f_ast - local has_implicit = not isalwaysreturn[block_ast] - return returns, has_implicit -end - --- temporary hack? -local function valnode_normalize(valnode) - if valnode then - return valnode.value - else - return T.none - end -end - - --- Gets return value at given return argument index, given list of `Return statements. --- Return value is a superset of corresponding types in list of statements. --- Example: {`Return{1,2,3}, `Return{1,3,'z'}} would return --- 1, T.number, and T.universal for retidx 1, 2 and 3 respectively. -local function get_return_value(returns, retidx) - if #returns == 0 then return T.none - elseif #returns == 1 then - return valnode_normalize(returns[1][retidx]) - else - local combined_value = valnode_normalize(returns[1][retidx]) - for i=2,#returns do - local cur_value = valnode_normalize(returns[i][retidx]) - combined_value = T.superset_types(combined_value, cur_value) - if combined_value == T.universal then -- can't expand set further - return combined_value - end - end - return combined_value - --TODO: handle values with possibly any number of return values, like f() - end -end - - --- Gets return values (or types) on `Function (or chunk) represented by given AST. -local function get_func_return_values(f_ast) - local returns, has_implicit = get_func_returns(f_ast) - if has_implicit then returns[#returns+1] = {tag='Return'} end - local returnvals = {n=0} - for retidx=1,math.huge do - local value = get_return_value(returns, retidx) - if value == T.none then break end - returnvals[#returnvals+1] = value - returnvals.n = returnvals.n + 1 - end - return returnvals -end --- Example: AST of `function(x) if x then return 1,2,3 else return 1,3,"z" end end` --- returns {1, T.number, T.universal}. - - --- Given list of values, return the first nvalues values plus the rest of the values --- as a tuple. Useful for things like --- local ok, values = valuesandtuple(1, pcall(f)) --- CATEGORY: utility function (list) -local function valuesandtuple(nvalues, ...) - if nvalues >= 1 then - return (...), valuesandtuple(nvalues-1, select(2, ...)) - else - return {n=select('#', ...), ...} - end -end - - --- Infers values of variables. Also marks dead code (ast.isdead). ---FIX/WARNING - this probably needs more work --- Sets top_ast.valueglobals, ast.value, ast.valueself --- CATEGORY: code interpretation -function M.infer_values(top_ast, tokenlist, src, report) - if not top_ast.valueglobals then top_ast.valueglobals = {} end - - - -- infer values - LA.walk(top_ast, function(ast) -- walk down - if ast.tag == 'Function' then - local paramlist_ast = ast[1] - for i=1,#paramlist_ast do local param_ast = paramlist_ast[i] - if param_ast.value == nil then param_ast.value = T.universal end - end - end - end, function(ast) -- walk up - -- process `require` statements. - if ast.tag == 'Local' or ast.tag == 'Localrec' then - local vars_ast, values_ast = ast[1], ast[2] - local valuelist = #values_ast > 0 and values_ast[#values_ast].valuelist - for i=1,#vars_ast do - local var_ast, value_ast = vars_ast[i], values_ast[i] - local value - if value_ast then - value = value_ast.value - elseif valuelist then - local vlidx = i - #values_ast + 1 - value = valuelist.sizeunknown and vlidx > valuelist.n and T.universal or valuelist[vlidx] - end - set_value(var_ast, value) - end - elseif ast.tag == 'Set' then -- note: implementation similar to 'Local' - local vars_ast, values_ast = ast[1], ast[2] - local valuelist = #values_ast > 0 and values_ast[#values_ast].valuelist - for i=1,#vars_ast do - local var_ast, value_ast = vars_ast[i], values_ast[i] - local value - if value_ast then - value = value_ast.value - elseif valuelist then - local vlidx = i - #values_ast + 1 - value = valuelist.sizeunknown and vlidx > valuelist.n and T.universal or valuelist[vlidx] - end - if var_ast.tag == 'Index' then - local t_ast, k_ast = var_ast[1], var_ast[2] - if not T.istype[t_ast.value] then -- note: don't mutate types - local v_ast = {value=value} - local ok; ok, var_ast.value = pzcall(tastnewindex, {t_ast, k_ast, v_ast}, t_ast, k_ast, v_ast) - if not ok then var_ast.value = T.error(var_ast.value) end - --FIX: propagate to localdefinition? - end - else - assert(var_ast.tag == 'Id', var_ast.tag) - if var_ast.localdefinition then - set_value(var_ast, value) - else -- global - local name = var_ast[1] - top_ast.valueglobals[name] = value - end - end - --FIX: propagate to definition or localdefinition? - end - elseif ast.tag == 'Fornum' then - local var_ast = ast[1] - set_value(var_ast, T.number) - elseif ast.tag == 'Forin' then - local varlist_ast, iter_ast = ast[1], ast[2] - if #iter_ast == 1 and iter_ast[1].tag == 'Call' and iter_ast[1][1].value == ipairs then - for i, var_ast in ipairs(varlist_ast) do - if i == 1 then set_value(var_ast, T.number) - -- handle the type of the value as the type of the first element - -- in the table that is a parameter for ipairs - elseif i == 2 then - local t_ast = iter_ast[1][2] - local value = T.universal - if (known(t_ast.value) or T.istabletype[t_ast.value]) then - local ok; ok, value = pzcall(tindex, {t_ast, {tag='Number', 1}}, t_ast.value, 1) - if not ok then value = T.error(t_ast.value) end - end - set_value(var_ast, value) - else set_value(var_ast, nil) end - end - elseif #iter_ast == 1 and iter_ast[1].tag == 'Call' and iter_ast[1][1].value == pairs then - local t_ast = iter_ast[1][2] - local value = T.universal - local key - if t_ast.value and (known(t_ast.value) or T.istabletype[t_ast.value]) then - key = next(t_ast.value) - local ok; ok, value = pzcall(tindex, {t_ast, {tag='String', key}}, t_ast.value, key) - if not ok then value = T.error(t_ast.value) end - end - - for i, var_ast in ipairs(varlist_ast) do - if i == 1 then set_value(var_ast, type(key)) - elseif i == 2 then set_value(var_ast, value) - else set_value(var_ast, nil) end - end - else -- general case, unknown iterator - for _, var_ast in ipairs(varlist_ast) do - set_value(var_ast, T.universal) - end - end - elseif ast.tag == 'Id' then - if ast.localdefinition then - local localdefinition = ast.localdefinition - if not localdefinition.isset then -- IMPROVE: support non-const (isset false) too - set_value(ast, localdefinition.value) - end - else -- global - local name = ast[1] - local v = top_ast.valueglobals[name] - if v ~= nil then - ast.value = v - else - local ok; ok, ast.value = pzcall(tindex, {{tag='Id', '_G'}, {tag='String', name}}, _G, name) - if not ok then ast.value = T.error(ast.value) end - end - end - elseif ast.tag == 'Index' then - local t_ast, k_ast = ast[1], ast[2] - if (known(t_ast.value) or T.istabletype[t_ast.value]) and known(k_ast.value) then - local ok; ok, ast.value = pzcall(tindex, {t_ast, k_ast}, t_ast.value, k_ast.value) - if not ok then ast.value = T.error(ast.value) end - end - elseif ast.tag == 'Call' or ast.tag == 'Invoke' then - -- Determine function to call (infer via index if method call). - local isinvoke = ast.tag == 'Invoke' - if isinvoke then - local t, k = ast[1].value, ast[2].value - if known(t) and known(k) then - local ok; ok, ast.valueself = pzcall(tindex, {ast[1], ast[2]}, t, k) - if not ok then ast.valueself = T.error(ast.valueself) end - end - end - local func; if isinvoke then func = ast.valueself else func = ast[1].value end - - -- Handle function call. - local argvalues_concrete = true; do -- true iff all arguments known precisely. - if #ast >= 2 then - local firstargvalue; if isinvoke then firstargvalue = ast.valueself else firstargvalue = ast[2].value end - if unknown(firstargvalue) then - argvalues_concrete = false - else -- test remaining args - for i=3,#ast do if unknown(ast[i].value) then argvalues_concrete = false; break end end - end - end - end - local found - if known(func) and argvalues_concrete then -- attempt call with concrete args - -- Get list of values of arguments. - local argvalues; do - argvalues = {n=#ast-1}; for i=1,argvalues.n do argvalues[i] = ast[i+1].value end - if isinvoke then argvalues[1] = ast.valueself end -- `self` - end - -- Any call to require is handled specially (source analysis). - if func == require and type(argvalues[1]) == 'string' then - local spath = tostring(ast.lineinfo.first):gsub(' (nparammax or math.huge) then - ast.note = "Too many arguments; " - iswarn = true - end - if iswarn then - ast.note = ast.note .. "expected " - .. nparammin .. (nparammax == nparammin and "" or " to " .. (nparammax or "infinity")) - .. " but got " - .. nargmin .. (nargmax == nargmin and "" or " to " .. (nargmax or "infinity")) .. "." - end - end - end - end) -end - - --- Resolves identifier to value [*] -function M.resolve_id(id, scope, valueglobals, _G) - local val - if scope[id] then - val = scope[id].value - elseif valueglobals[id] ~= nil then - val = valueglobals[id] - else - val = _G[id] -- assumes not raise - end - return val -end - --- Resolves prefix chain expression to value. [*] --- On error returns nil and error object -function M.resolve_prefixexp(ids, scope, valueglobals, _G) - local _1 = M.resolve_id(ids[1], scope, valueglobals, _G) - local ok, err = pzcall(function() - for i=2,#ids do - _1 = _1[ids[i]] - end - end, {}) - if err then return nil, err or '?' end - return _1 -end - --- Gets local scope at given 1-indexed char position -function M.get_scope(pos1, ast, tokenlist) - local mast, isafter = LA.current_statementblock(ast, tokenlist, pos1) - local scope = LG.variables_in_scope(mast, isafter) - return scope -end - --- Gets names in prefix expression ids (as returned by resolve_prefixexp). [*] -function M.names_in_prefixexp(ids, pos, ast, tokenlist) - local scope = M.get_scope(pos, ast, tokenlist) - --FIX: above does not handle `for x=1,2 do| print(x) end` where '|' is cursor position. - local names = {} - if #ids == 0 then -- global - for name in pairs(scope) do names[#names+1] = name end - for name in pairs(ast.valueglobals) do names[#names+1] = name end - for name in pairs(_G) do names[#names+1] = name end - else -- field - local t, err_ = M.resolve_prefixexp(ids, scope, ast.valueglobals, _G) - if type(t) == 'table' then -- note: err_ implies false here - for name in pairs(t) do names[#names+1] = name end - end - end - return names -end - --- Gets signature (function argument string or helpinfo string) on value. --- Returns nil on not found. -function M.get_signature_of_value(value) - local info = M.debuginfo[value] -- first try this - if info and info.fast then - local fidx, lidx = LA.ast_idx_range_in_tokenlist(info.tokenlist, info.fast[1]) - local ts = {} - if fidx then - for i=fidx,lidx do - local token = info.tokenlist[i] - ts[#ts+1] = token.tag == 'Dots' and '...' or token[1] - end - end - local sig = 'function(' .. table.concat(ts, ' ') .. ')' - if info.retvals then - local vals = info.retvals - local ts = {} - if vals.n == 0 then - sig = sig .. " no returns" - else - for i=1,vals.n do local val = vals[i] - ts[#ts+1] = T.istype[val] and tostring(val) or LD.dumpstring(val) --Q:dumpstring too verbose? - end - sig = sig .. " returns " .. table.concat(ts, ", ") - end - end - return sig - end - local sig = LS.value_signatures[value] -- else try this - return sig -end - - --- Gets signature (function argument string or helpinfo string) on variable ast. --- Returns nil on not found. -function M.get_signature(ast) - if known(ast.value) then - return M.get_signature_of_value(ast.value) - end -end - - --- Gets 1-indexed character (or line) position and filename of --- definition associated with AST node (if any). -function M.ast_to_definition_position(ast, tokenlist) - local local_ast = ast.localdefinition - local fpos, fline, path - if local_ast then - local tidx = LA.ast_idx_range_in_tokenlist(tokenlist, local_ast) - if tidx then - local spath = tostring(ast.lineinfo.first):gsub('' then - isoutputs = true - elseif isoutputs then - outputs[#outputs+1] = v; outputs.n = outputs.n + 1 - else - inputs[#inputs+1] = v; inputs.n = inputs.n + 1 - end - end - M.mock_functions[func] = {inputs=inputs, outputs=outputs} -end - - -mockfunction(math.abs, 'N', '->', {'N',0,math.huge}) -mockfunction(math.acos, {'N',-1,1}, '->', {'N',0,math.pi/2}) -mockfunction(math.asin, {'N',-1,1}, '->', {'N',-math.pi/2,math.pi/2}) -mockfunction(math.atan, {'N',-math.huge,math.huge}, '->', - {'N',-math.pi/2,math.pi/2}) ---FIX atan2 -mockfunction(math.ceil, 'N','->','I') -mockfunction(math.cos, 'N','->',{'N',-1,1}) -mockfunction(math.cosh, 'N','->',{'N',1,math.huge}) -mockfunction(math.deg, 'N','->','N') -mockfunction(math.exp, 'N','->',{'N',0,math.huge}) -mockfunction(math.floor, 'N','->','I') -mockfunction(math.fmod, 'N','N','->','N') -mockfunction(math.frexp, 'N','->',{'N',-1,1},'->','I') -mockfunction(math.ldexp, {'N','I'},'->','N') -mockfunction(math.log, {'N',0,math.huge},'->','N') -mockfunction(math.log10, {'N',0,math.huge},'->','N') --- function max(...) print 'NOT IMPL'end --- function min(...) print 'NOT IMPL'end -mockfunction(math.modf, 'N','->','I',{'N',-1,1}) - -mockfunction(math.pow, 'N','N','->','N') -- improve? -mockfunction(math.rad, 'N','->','N') --- random = function() print 'NOT IMPL' end -mockfunction(math.randomseed, 'N') -mockfunction(math.sin, 'N','->',{'N',-1,1}) -mockfunction(math.sinh, 'N','->','N') -mockfunction(math.sqrt, {'N',0,math.huge},'->',{'N',0,math.huge}) -mockfunction(math.tan, 'N','->','N') -- improve? -mockfunction(math.tanh, 'N','->',{'N',-1,1}) - - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/typecheck.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/typecheck.lua deleted file mode 100644 index 549f8fe..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/typecheck.lua +++ /dev/null @@ -1,40 +0,0 @@ --- luainspect.typecheck - Type definitions used to check LuaInspect itself. --- --- (c) 2010 David Manura, MIT License. - -local T = require "luainspect.types" - -local ast_mt = {__tostring = function(s) return 'AST' end} - -return function(context) - -- AST type. - local ast = T.table { - tag = T.string, - lineinfo=T.table{first=T.table{comments=T.table{T.table{T.string,T.number,T.number}},T.number,T.number,T.number,T.string}, - ast=T.table{comments=T.table{T.table{T.string,T.number,T.number}},T.number,T.number,T.number,T.string}}, - isfield=T.boolean, tag2=T.string, - value=T.universal, valueself=T.number, valuelist=T.table{n=T.number, isvaluepegged=T.boolean}, - resolvedname=T.string, definedglobal=T.boolean, id=T.number, isparam=T.boolean, isset=T.boolean, isused=T.boolean, - isignore=T.boolean, - functionlevel=T.number, localmasked=T.boolean, note=T.string, nocollect=T.table{}, isdead=T.boolean} - -- FIX: some of these are "boolean or nil" actually - ast.localdefinition=ast; ast.localmasking = ast - ast.previous = ast; ast.parent = ast - ast.seevalue = ast; ast.seenote=ast - setmetatable(ast, ast_mt) - - ast[1] = ast; ast[2] = ast - context.apply_value('ast$', ast) - - -- Token type. - context.apply_value('token$', T.table{ - tag=T.string, fpos=T.number, lpos=T.number, keywordid=T.number, ast=ast, [1]=T.string - }) - - -- Lua source code string type. - context.apply_value('src$', '') - - -- SciTE syler object type. - local nf = function()end - context.apply_value('^styler$', T.table{SetState=nf, More=nf, Current=nf, Forward=nf, StartStyling=nf, EndStyling=nf, language=T.string}) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/types.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/types.lua deleted file mode 100644 index 7994eb0..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/luainspect/types.lua +++ /dev/null @@ -1,130 +0,0 @@ -local T = {} -- types - --- istype[o] iff o represents a type (i.e. set of values) -T.istype = {} - --- iserror[o] iff o represents an error type (created via T.error). -T.iserror = {} - --- istabletype[o] iff o represents a table type (created by T.table). -T.istabletype = {} - --- Number type -T.number = {} -setmetatable(T.number, T.number) -function T.number.__tostring(self) - return 'number' -end -T.istype[T.number] = true - --- String type -T.string = {} -setmetatable(T.string, T.string) -function T.string.__tostring(self) - return 'string' -end -T.istype[T.string] = true - --- Boolean type -T.boolean = {} -setmetatable(T.boolean, T.boolean) -function T.boolean.__tostring(self) - return 'boolean' -end -T.istype[T.boolean] = true - --- Table type -function T.table(t) - T.istype[t] = true - T.istabletype[t] = true - return t -end - --- Universal type. This is a superset of all other types. -T.universal = {} -setmetatable(T.universal, T.universal) -function T.universal.__tostring(self) - return 'unknown' -end -T.istype[T.universal] = true - --- nil type. Represents `nil` but can be stored in tables. -T['nil'] = {} -setmetatable(T['nil'], T['nil']) -T['nil'].__tostring = function(self) - return 'nil' -end -T.istype[T['nil']] = true - --- None type. Represents a non-existent value, in a similar way --- that `none` is used differently from `nil` in the Lua C API. -T.none = {} -setmetatable(T.none, T.none) -function T.none.__tostring(self) - return 'none' -end -T.istype[T.none] = true - --- Error type -local CError = {}; CError.__index = CError -function CError.__tostring(self) return "error:" .. tostring(self.value) end -function T.error(val) - local self = setmetatable({value=val}, CError) - T.istype[self] = true - T.iserror[self] = true - return self -end - - --- Gets a type that is a superset of the two given types. -function T.superset_types(a, b) - if T.iserror[a] then return a end - if T.iserror[b] then return b end - if rawequal(a, b) then -- note: including nil == nil - return a - elseif type(a) == 'string' or a == T.string then - if type(b) == 'string' or b == T.string then - return T.string - else - return T.universal - end - elseif type(a) == 'number' or a == T.number then - if type(b) == 'number' or b == T.number then - return T.number - else - return T.universal - end - elseif type(a) == 'boolean' or a == T.boolean then - if type(b) == 'boolean' or b == T.boolean then - return T.boolean - else - return T.universal - end - else - return T.universal -- IMPROVE - end -end ---[[TESTS: -assert(T.superset_types(2, 2) == 2) -assert(T.superset_types(2, 3) == T.number) -assert(T.superset_types(2, T.number) == T.number) -assert(T.superset_types(T.number, T.string) == T.universal) -print 'DONE' ---]] - --- Determines whether type `o` certainly evaluates to true (true), --- certainly evaluates to false (false) or could evaluate to either --- true of false ('?'). -function T.boolean_cast(o) - if T.iserror[o] then -- special case - return '?' - elseif o == nil or o == false or o == T['nil'] then -- all subsets of {nil, false} - return false - elseif o == T.universal or o == T.boolean then -- all supersets of boolean - return '?' - else -- all subsets of universal - {nil, false} - return true - end -end - -return T diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler.lua deleted file mode 100644 index e534cf4..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler.lua +++ /dev/null @@ -1,162 +0,0 @@ ---------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Convert between various code representation formats. Atomic --- converters are written in extenso, others are composed automatically --- by chaining the atomic ones together in a closure. --- --- Supported formats are: --- --- * srcfile: the name of a file containing sources. --- * src: these sources as a single string. --- * lexstream: a stream of lexemes. --- * ast: an abstract syntax tree. --- * proto: a (Yueliang) struture containing a high level --- representation of bytecode. Largely based on the --- Proto structure in Lua's VM --- * bytecode: a string dump of the function, as taken by --- loadstring() and produced by string.dump(). --- * function: an executable lua function in RAM. --- --------------------------------------------------------------------------------- - -require 'checks' - -local M = { } - --------------------------------------------------------------------------------- --- Order of the transformations. if 'a' is on the left of 'b', then a 'a' can --- be transformed into a 'b' (but not the other way around). --- M.sequence goes for numbers to format names, M.order goes from format --- names to numbers. --------------------------------------------------------------------------------- -M.sequence = { - 'srcfile', 'src', 'lexstream', 'ast', 'proto', 'bytecode', 'function' } - -local arg_types = { - srcfile = { 'string', '?string' }, - src = { 'string', '?string' }, - lexstream = { 'lexer.stream', '?string' }, - ast = { 'table', '?string' }, - proto = { 'table', '?string' }, - bytecode = { 'string', '?string' }, -} - -M.order= { }; for a,b in pairs(M.sequence) do M.order[b]=a end - -local CONV = { } -- conversion metatable __index - -function CONV :srcfile_to_src(x, name) - checks('metalua.compiler', 'string', '?string') - name = name or '@'..x - local f, msg = io.open (x, 'rb') - if not f then error(msg) end - local r, msg = f :read '*a' - if not r then error("Cannot read file '"..x.."': "..msg) end - f :close() - return r, name -end - -function CONV :src_to_lexstream(src, name) - checks('metalua.compiler', 'string', '?string') - local r = self.parser.lexer :newstream (src, name) - return r, name -end - -function CONV :lexstream_to_ast(lx, name) - checks('metalua.compiler', 'lexer.stream', '?string') - local r = self.parser.chunk(lx) - r.source = name - return r, name -end - -local bytecode_compiler = nil -- cache to avoid repeated `pcall(require(...))` -local function get_bytecode_compiler() - if bytecode_compiler then return bytecode_compiler else - local status, result = pcall(require, 'metalua.compiler.bytecode') - if status then - bytecode_compiler = result - return result - elseif string.match(result, "not found") then - error "Compilation only available with full Metalua" - else error (result) end - end -end - -function CONV :ast_to_proto(ast, name) - checks('metalua.compiler', 'table', '?string') - return get_bytecode_compiler().ast_to_proto(ast, name), name -end - -function CONV :proto_to_bytecode(proto, name) - return get_bytecode_compiler().proto_to_bytecode(proto), name -end - -function CONV :bytecode_to_function(bc, name) - checks('metalua.compiler', 'string', '?string') - return loadstring(bc, name) -end - --- Create all sensible combinations -for i=1,#M.sequence do - local src = M.sequence[i] - for j=i+2, #M.sequence do - local dst = M.sequence[j] - local dst_name = src.."_to_"..dst - local my_arg_types = arg_types[src] - local functions = { } - for k=i, j-1 do - local name = M.sequence[k].."_to_"..M.sequence[k+1] - local f = assert(CONV[name], name) - table.insert (functions, f) - end - CONV[dst_name] = function(self, a, b) - checks('metalua.compiler', unpack(my_arg_types)) - for _, f in ipairs(functions) do - a, b = f(self, a, b) - end - return a, b - end - --printf("Created M.%s out of %s", dst_name, table.concat(n, ', ')) - end -end - - --------------------------------------------------------------------------------- --- This one goes in the "wrong" direction, cannot be composed. --------------------------------------------------------------------------------- -function CONV :function_to_bytecode(...) return string.dump(...) end - -function CONV :ast_to_src(...) - require 'metalua.loader' -- ast_to_string isn't written in plain lua - return require 'metalua.compiler.ast_to_src' (...) -end - -local MT = { __index=CONV, __type='metalua.compiler' } - -function M.new() - local parser = require 'metalua.compiler.parser' .new() - local self = { parser = parser } - setmetatable(self, MT) - return self -end - -return M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser.lua deleted file mode 100644 index 74997ae..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser.lua +++ /dev/null @@ -1,42 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - --- Export all public APIs from sub-modules, squashed into a flat spacename - -local MT = { __type='metalua.compiler.parser' } - -local MODULE_REL_NAMES = { "annot.grammar", "expr", "meta", "misc", - "stat", "table", "ext" } - -local function new() - local M = { - lexer = require "metalua.compiler.parser.lexer" (); - extensions = { } } - for _, rel_name in ipairs(MODULE_REL_NAMES) do - local abs_name = "metalua.compiler.parser."..rel_name - local extender = require (abs_name) - if not M.extensions[abs_name] then - if type (extender) == 'function' then extender(M) end - M.extensions[abs_name] = extender - end - end - return setmetatable(M, MT) -end - -return { new = new } diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/generator.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/generator.lua deleted file mode 100644 index a8fcd62..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/generator.lua +++ /dev/null @@ -1,48 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - -require 'checks' -local gg = require 'metalua.grammar.generator' -local M = { } - -function M.opt(mlc, primary, a_type) - checks('table', 'table|function', 'string') - return gg.sequence{ - primary, - gg.onkeyword{ "#", function() return assert(mlc.annot[a_type]) end }, - builder = function(x) - local t, annot = unpack(x) - return annot and { tag='Annot', t, annot } or t - end } -end - --- split a list of "foo" and "`Annot{foo, annot}" into a list of "foo" --- and a list of "annot". --- No annot list is returned if none of the elements were annotated. -function M.split(lst) - local x, a, some = { }, { }, false - for i, p in ipairs(lst) do - if p.tag=='Annot' then - some, x[i], a[i] = true, unpack(p) - else x[i] = p end - end - if some then return x, a else return lst end -end - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/grammar.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/grammar.lua deleted file mode 100644 index 7ce3ec4..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/grammar.lua +++ /dev/null @@ -1,112 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - -local gg = require 'metalua.grammar.generator' - -return function(M) - local _M = gg.future(M) - M.lexer :add '->' - local A = { } - local _A = gg.future(A) - M.annot = A - - -- Type identifier: Lua keywords such as `"nil"` allowed. - function M.annot.tid(lx) - local w = lx :next() - local t = w.tag - if t=='Keyword' and w[1] :match '^[%a_][%w_]*$' or w.tag=='Id' - then return {tag='TId'; lineinfo=w.lineinfo; w[1]} - else return gg.parse_error (lx, 'tid expected') end - end - - local field_types = { var='TVar'; const='TConst'; - currently='TCurrently'; field='TField' } - - -- TODO check lineinfo - function M.annot.tf(lx) - local tk = lx:next() - local w = tk[1] - local tag = field_types[w] - if not tag then error ('Invalid field type '..w) - elseif tag=='TField' then return {tag='TField'} else - local te = M.te(lx) - return {tag=tag; te} - end - end - - M.annot.tebar_content = gg.list{ - name = 'tebar content', - primary = _A.te, - separators = { ",", ";" }, - terminators = ")" } - - M.annot.tebar = gg.multisequence{ - name = 'annot.tebar', - --{ '*', builder = 'TDynbar' }, -- maybe not user-available - { '(', _A.tebar_content, ')', - builder = function(x) return x[1] end }, - { _A.te } - } - - M.annot.te = gg.multisequence{ - name = 'annot.te', - { _A.tid, builder=function(x) return x[1] end }, - { '*', builder = 'TDyn' }, - { "[", - gg.list{ - primary = gg.sequence{ - _M.expr, "=", _A.tf, - builder = 'TPair' - }, - separators = { ",", ";" }, - terminators = { "]", "|" } }, - gg.onkeyword{ "|", _A.tf }, - "]", - builder = function(x) - local fields, other = unpack(x) - return { tag='TTable', other or {tag='TField'}, fields } - end }, -- "[ ... ]" - { '(', _A.tebar_content, ')', '->', '(', _A.tebar_content, ')', - builder = function(x) - local p, r = unpack(x) - return {tag='TFunction', p, r } - end } } - - M.annot.ts = gg.multisequence{ - name = 'annot.ts', - { 'return', _A.tebar_content, builder='TReturn' }, - { _A.tid, builder = function(x) - if x[1][1]=='pass' then return {tag='TPass'} - else error "Bad statement type" end - end } } - --- TODO: add parsers for statements: --- #return tebar --- #alias = te --- #ell = tf ---[[ - M.annot.stat_annot = gg.sequence{ - gg.list{ primary=_A.tid, separators='.' }, - '=', - XXX??, - builder = 'Annot' } ---]] - - return M.annot -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/common.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/common.lua deleted file mode 100644 index 1d6290e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/common.lua +++ /dev/null @@ -1,27 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - --- Shared common parser table. It will be filled by parser.init(), --- and every other module will be able to call its elements at runtime. --- --- If the table was directly created in parser.init, a circular --- dependency would be created: parser.init depends on other modules to fill the table, --- so other modules can't simultaneously depend on it. - -return { } \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/expr.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/expr.lua deleted file mode 100644 index b162e8a..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/expr.lua +++ /dev/null @@ -1,213 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- --- Exported API: --- * [mlp.expr()] --- * [mlp.expr_list()] --- * [mlp.func_val()] --- -------------------------------------------------------------------------------- - -local pp = require 'metalua.pprint' -local gg = require 'metalua.grammar.generator' -local annot = require 'metalua.compiler.parser.annot.generator' - -return function(M) - local _M = gg.future(M) - local _table = gg.future(M, 'table') - local _meta = gg.future(M, 'meta') -- TODO move to ext? - local _annot = gg.future(M, 'annot') -- TODO move to annot - - -------------------------------------------------------------------------------- - -- Non-empty expression list. Actually, this isn't used here, but that's - -- handy to give to users. - -------------------------------------------------------------------------------- - M.expr_list = gg.list{ primary=_M.expr, separators="," } - - -------------------------------------------------------------------------------- - -- Helpers for function applications / method applications - -------------------------------------------------------------------------------- - M.func_args_content = gg.list{ - name = "function arguments", - primary = _M.expr, - separators = ",", - terminators = ")" } - - -- Used to parse methods - M.method_args = gg.multisequence{ - name = "function argument(s)", - { "{", _table.content, "}" }, - { "(", _M.func_args_content, ")", builder = unpack }, - { "+{", _meta.quote_content, "}" }, - -- TODO lineinfo? - function(lx) local r = M.opt_string(lx); return r and {r} or { } end } - - -------------------------------------------------------------------------------- - -- [func_val] parses a function, from opening parameters parenthese to - -- "end" keyword included. Used for anonymous functions as well as - -- function declaration statements (both local and global). - -- - -- It's wrapped in a [_func_val] eta expansion, so that when expr - -- parser uses the latter, they will notice updates of [func_val] - -- definitions. - -------------------------------------------------------------------------------- - M.func_params_content = gg.list{ - name="function parameters", - gg.multisequence{ { "...", builder = "Dots" }, annot.opt(M, _M.id, 'te') }, - separators = ",", terminators = {")", "|"} } - - -- TODO move to annot - M.func_val = gg.sequence{ - name = "function body", - "(", _M.func_params_content, ")", _M.block, "end", - builder = function(x) - local params, body = unpack(x) - local annots, some = { }, false - for i, p in ipairs(params) do - if p.tag=='Annot' then - params[i], annots[i], some = p[1], p[2], true - else annots[i] = false end - end - if some then return { tag='Function', params, body, annots } - else return { tag='Function', params, body } end - end } - - local func_val = function(lx) return M.func_val(lx) end - - -------------------------------------------------------------------------------- - -- Default parser for primary expressions - -------------------------------------------------------------------------------- - function M.id_or_literal (lx) - local a = lx:next() - if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then - local msg - if a.tag=='Eof' then - msg = "End of file reached when an expression was expected" - elseif a.tag=='Keyword' then - msg = "An expression was expected, and `"..a[1].. - "' can't start an expression" - else - msg = "Unexpected expr token " .. pp.tostring (a) - end - gg.parse_error (lx, msg) - end - return a - end - - - -------------------------------------------------------------------------------- - -- Builder generator for operators. Wouldn't be worth it if "|x|" notation - -- were allowed, but then lua 5.1 wouldn't compile it - -------------------------------------------------------------------------------- - - -- opf1 = |op| |_,a| `Op{ op, a } - local function opf1 (op) return - function (_,a) return { tag="Op", op, a } end end - - -- opf2 = |op| |a,_,b| `Op{ op, a, b } - local function opf2 (op) return - function (a,_,b) return { tag="Op", op, a, b } end end - - -- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed) - local function opf2r (op) return - function (a,_,b) return { tag="Op", op, b, a } end end - - local function op_ne(a, _, b) - -- This version allows to remove the "ne" operator from the AST definition. - -- However, it doesn't always produce the exact same bytecode as Lua 5.1. - return { tag="Op", "not", - { tag="Op", "eq", a, b, lineinfo= { - first = a.lineinfo.first, last = b.lineinfo.last } } } - end - - - -------------------------------------------------------------------------------- - -- - -- complete expression - -- - -------------------------------------------------------------------------------- - - -- FIXME: set line number. In [expr] transformers probably - M.expr = gg.expr { - name = "expression", - primary = gg.multisequence{ - name = "expr primary", - { "(", _M.expr, ")", builder = "Paren" }, - { "function", _M.func_val, builder = unpack }, - { "-{", _meta.splice_content, "}", builder = unpack }, - { "+{", _meta.quote_content, "}", builder = unpack }, - { "nil", builder = "Nil" }, - { "true", builder = "True" }, - { "false", builder = "False" }, - { "...", builder = "Dots" }, - { "{", _table.content, "}", builder = unpack }, - _M.id_or_literal }, - - infix = { - name = "expr infix op", - { "+", prec = 60, builder = opf2 "add" }, - { "-", prec = 60, builder = opf2 "sub" }, - { "*", prec = 70, builder = opf2 "mul" }, - { "/", prec = 70, builder = opf2 "div" }, - { "%", prec = 70, builder = opf2 "mod" }, - { "^", prec = 90, builder = opf2 "pow", assoc = "right" }, - { "//", prec = 70, builder = opf2 "idiv" }, - { "&", prec = 36, builder = opf2 "band" }, - { "|", prec = 32, builder = opf2 "bor" }, - { "~", prec = 34, builder = opf2 "bxor" }, - { "<<", prec = 38, builder = opf2 "shl" }, - { ">>", prec = 38, builder = opf2 "shr" }, - { "..", prec = 40, builder = opf2 "concat", assoc = "right" }, - { "==", prec = 30, builder = opf2 "eq" }, - { "~=", prec = 30, builder = op_ne }, - { "<", prec = 30, builder = opf2 "lt" }, - { "<=", prec = 30, builder = opf2 "le" }, - { ">", prec = 30, builder = opf2r "lt" }, - { ">=", prec = 30, builder = opf2r "le" }, - { "and",prec = 20, builder = opf2 "and" }, - { "or", prec = 10, builder = opf2 "or" } }, - - prefix = { - name = "expr prefix op", - { "not", prec = 80, builder = opf1 "not" }, - { "#", prec = 80, builder = opf1 "len" }, - { "~", prec = 80, builder = opf2 "bnot" }, - { "-", prec = 80, builder = opf1 "unm" } }, - - suffix = { - name = "expr suffix op", - { "[", _M.expr, "]", builder = function (tab, idx) - return {tag="Index", tab, idx[1]} end}, - { ".", _M.id, builder = function (tab, field) - return {tag="Index", tab, _M.id2string(field[1])} end }, - { "(", _M.func_args_content, ")", builder = function(f, args) - return {tag="Call", f, unpack(args[1])} end }, - { "{", _table.content, "}", builder = function (f, arg) - return {tag="Call", f, arg[1]} end}, - { ":", _M.id, _M.method_args, builder = function (obj, post) - local m_name, args = unpack(post) - return {tag="Invoke", obj, _M.id2string(m_name), unpack(args)} end}, - { "+{", _meta.quote_content, "}", builder = function (f, arg) - return {tag="Call", f, arg[1] } end }, - default = { name="opt_string_arg", parse = _M.opt_string, builder = function(f, arg) - return {tag="Call", f, arg } end } } } - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/ext.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/ext.lua deleted file mode 100644 index 4e9d395..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/ext.lua +++ /dev/null @@ -1,96 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Non-Lua syntax extensions --- --------------------------------------------------------------------------------- - -local gg = require 'metalua.grammar.generator' - -return function(M) - - local _M = gg.future(M) - - --------------------------------------------------------------------------- - -- Algebraic Datatypes - ---------------------------------------------------------------------------- - local function adt (lx) - local node = _M.id (lx) - local tagval = node[1] - -- tagkey = `Pair{ `String "key", `String{ -{tagval} } } - local tagkey = { tag="Pair", {tag="String", "tag"}, {tag="String", tagval} } - if lx:peek().tag == "String" or lx:peek().tag == "Number" then - -- TODO support boolean litterals - return { tag="Table", tagkey, lx:next() } - elseif lx:is_keyword (lx:peek(), "{") then - local x = M.table.table (lx) - table.insert (x, 1, tagkey) - return x - else return { tag="Table", tagkey } end - end - - M.adt = gg.sequence{ "`", adt, builder = unpack } - - M.expr.primary :add(M.adt) - - ---------------------------------------------------------------------------- - -- Anonymous lambda - ---------------------------------------------------------------------------- - M.lambda_expr = gg.sequence{ - "|", _M.func_params_content, "|", _M.expr, - builder = function (x) - local li = x[2].lineinfo - return { tag="Function", x[1], - { {tag="Return", x[2], lineinfo=li }, lineinfo=li } } - end } - - M.expr.primary :add (M.lambda_expr) - - -------------------------------------------------------------------------------- - -- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell. - -------------------------------------------------------------------------------- - function M.expr_in_backquotes (lx) return M.expr(lx, 35) end -- 35=limited precedence - M.expr.infix :add{ name = "infix function", - "`", _M.expr_in_backquotes, "`", prec = 35, assoc="left", - builder = function(a, op, b) return {tag="Call", op[1], a, b} end } - - -------------------------------------------------------------------------------- - -- C-style op+assignments - -- TODO: no protection against side-effects in LHS vars. - -------------------------------------------------------------------------------- - local function op_assign(kw, op) - local function rhs(a, b) return { tag="Op", op, a, b } end - local function f(a,b) - if #a ~= #b then gg.parse_error "assymetric operator+assignment" end - local right = { } - local r = { tag="Set", a, right } - for i=1, #a do right[i] = { tag="Op", op, a[i], b[i] } end - return r - end - M.lexer :add (kw) - M.assignments[kw] = f - end - - local ops = { add='+='; sub='-='; mul='*='; div='/=' } - for ast_op_name, keyword in pairs(ops) do op_assign(keyword, ast_op_name) end - - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/lexer.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/lexer.lua deleted file mode 100644 index 024c479..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/lexer.lua +++ /dev/null @@ -1,44 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2014 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - ----------------------------------------------------------------------- --- Generate a new lua-specific lexer, derived from the generic lexer. ----------------------------------------------------------------------- - -local generic_lexer = require 'metalua.grammar.lexer' - -return function() - local lexer = generic_lexer.lexer :clone() - - local keywords = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", - "goto", -- Lua5.2 - "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "...", "..", "==", ">=", "<=", "~=", - "<<", ">>", "//", -- Lua5.3 - "::", -- Lua5.2 - "+{", "-{" } -- Metalua - - for _, w in ipairs(keywords) do lexer :add (w) end - - return lexer -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/meta.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/meta.lua deleted file mode 100644 index 71eb3c3..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/meta.lua +++ /dev/null @@ -1,138 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2014 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - --- Compile-time metaprogramming features: splicing ASTs generated during compilation, --- AST quasi-quoting helpers. - -local gg = require 'metalua.grammar.generator' - -return function(M) - local _M = gg.future(M) - M.meta={ } - local _MM = gg.future(M.meta) - - -------------------------------------------------------------------------------- - -- External splicing: compile an AST into a chunk, load and evaluate - -- that chunk, and replace the chunk by its result (which must also be - -- an AST). - -------------------------------------------------------------------------------- - - -- TODO: that's not part of the parser - function M.meta.eval (ast) - -- TODO: should there be one mlc per splice, or per parser instance? - local mlc = require 'metalua.compiler'.new() - local f = mlc :ast_to_function (ast, '=splice') - local result=f(M) -- splices act on the current parser - return result - end - - ---------------------------------------------------------------------------- - -- Going from an AST to an AST representing that AST - -- the only hash-part key being lifted is `"tag"`. - -- Doesn't lift subtrees protected inside a `Splice{ ... }. - -- e.g. change `Foo{ 123 } into - -- `Table{ `Pair{ `String "tag", `String "foo" }, `Number 123 } - ---------------------------------------------------------------------------- - local function lift (t) - --print("QUOTING:", table.tostring(t, 60,'nohash')) - local cases = { } - function cases.table (t) - local mt = { tag = "Table" } - --table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } }) - if t.tag == "Splice" then - assert (#t==1, "Invalid splice") - local sp = t[1] - return sp - elseif t.tag then - table.insert (mt, { tag="Pair", lift "tag", lift(t.tag) }) - end - for _, v in ipairs (t) do - table.insert (mt, lift(v)) - end - return mt - end - function cases.number (t) return { tag = "Number", t, quote = true } end - function cases.string (t) return { tag = "String", t, quote = true } end - function cases.boolean (t) return { tag = t and "True" or "False", t, quote = true } end - local f = cases [type(t)] - if f then return f(t) else error ("Cannot quote an AST containing "..tostring(t)) end - end - M.meta.lift = lift - - -------------------------------------------------------------------------------- - -- when this variable is false, code inside [-{...}] is compiled and - -- avaluated immediately. When it's true (supposedly when we're - -- parsing data inside a quasiquote), [-{foo}] is replaced by - -- [`Splice{foo}], which will be unpacked by [quote()]. - -------------------------------------------------------------------------------- - local in_a_quote = false - - -------------------------------------------------------------------------------- - -- Parse the inside of a "-{ ... }" - -------------------------------------------------------------------------------- - function M.meta.splice_content (lx) - local parser_name = "expr" - if lx:is_keyword (lx:peek(2), ":") then - local a = lx:next() - lx:next() -- skip ":" - assert (a.tag=="Id", "Invalid splice parser name") - parser_name = a[1] - end - -- TODO FIXME running a new parser with the old lexer?! - local parser = require 'metalua.compiler.parser'.new() - local ast = parser [parser_name](lx) - if in_a_quote then -- only prevent quotation in this subtree - --printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60)) - return { tag="Splice", ast } - else -- convert in a block, eval, replace with result - if parser_name == "expr" then ast = { { tag="Return", ast } } - elseif parser_name == "stat" then ast = { ast } - elseif parser_name ~= "block" then - error ("splice content must be an expr, stat or block") end - --printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60)) - return M.meta.eval (ast) - end - end - - M.meta.splice = gg.sequence{ "-{", _MM.splice_content, "}", builder=unpack } - - -------------------------------------------------------------------------------- - -- Parse the inside of a "+{ ... }" - -------------------------------------------------------------------------------- - function M.meta.quote_content (lx) - local parser - if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content } - local parser_name = M.id(lx)[1] - parser = M[parser_name] - lx:next() -- skip ":" - else -- +{ content } - parser = M.expr - end - - local prev_iq = in_a_quote - in_a_quote = true - --print("IN_A_QUOTE") - local content = parser (lx) - local q_content = M.meta.lift (content) - in_a_quote = prev_iq - return q_content - end - - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/misc.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/misc.lua deleted file mode 100644 index 22a63f4..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/misc.lua +++ /dev/null @@ -1,147 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- --- Summary: metalua parser, miscellaneous utility functions. --- -------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Exported API: --- * [mlp.fget()] --- * [mlp.id()] --- * [mlp.opt_id()] --- * [mlp.id_list()] --- * [mlp.string()] --- * [mlp.opt_string()] --- * [mlp.id2string()] --- --------------------------------------------------------------------------------- - -local gg = require 'metalua.grammar.generator' - --- TODO: replace splice-aware versions with naive ones, move etensions in ./meta - -return function(M) - local _M = gg.future(M) - - - -------------------------------------------------------------------------------- - -- Try to read an identifier (possibly as a splice), or return [false] if no - -- id is found. - -------------------------------------------------------------------------------- - function M.opt_id (lx) - local a = lx:peek(); - if lx:is_keyword (a, "-{") then - local v = M.meta.splice(lx) - if v.tag ~= "Id" and v.tag ~= "Splice" then - gg.parse_error(lx, "Bad id splice") - end - return v - elseif a.tag == "Id" then return lx:next() - else return false end - end - - -------------------------------------------------------------------------------- - -- Mandatory reading of an id: causes an error if it can't read one. - -------------------------------------------------------------------------------- - function M.id (lx) - return M.opt_id (lx) or gg.parse_error(lx,"Identifier expected") - end - - -------------------------------------------------------------------------------- - -- Common helper function - -------------------------------------------------------------------------------- - M.id_list = gg.list { primary = _M.id, separators = "," } - - -------------------------------------------------------------------------------- - -- Converts an identifier into a string. Hopefully one day it'll handle - -- splices gracefully, but that proves quite tricky. - -------------------------------------------------------------------------------- - function M.id2string (id) - --print("id2string:", disp.ast(id)) - if id.tag == "Id" then id.tag = "String"; return id - elseif id.tag == "Splice" then - error ("id2string on splice not implemented") - -- Evaluating id[1] will produce `Id{ xxx }, - -- and we want it to produce `String{ xxx }. - -- The following is the plain notation of: - -- +{ `String{ `Index{ `Splice{ -{id[1]} }, `Number 1 } } } - return { tag="String", { tag="Index", { tag="Splice", id[1] }, - { tag="Number", 1 } } } - else error ("Identifier expected: "..table.tostring(id, 'nohash')) end - end - - -------------------------------------------------------------------------------- - -- Read a string, possibly spliced, or return an error if it can't - -------------------------------------------------------------------------------- - function M.string (lx) - local a = lx:peek() - if lx:is_keyword (a, "-{") then - local v = M.meta.splice(lx) - if v.tag ~= "String" and v.tag ~= "Splice" then - gg.parse_error(lx,"Bad string splice") - end - return v - elseif a.tag == "String" then return lx:next() - else error "String expected" end - end - - -------------------------------------------------------------------------------- - -- Try to read a string, or return false if it can't. No splice allowed. - -------------------------------------------------------------------------------- - function M.opt_string (lx) - return lx:peek().tag == "String" and lx:next() - end - - -------------------------------------------------------------------------------- - -- Chunk reader: block + Eof - -------------------------------------------------------------------------------- - function M.skip_initial_sharp_comment (lx) - -- Dirty hack: I'm happily fondling lexer's private parts - -- FIXME: redundant with lexer:newstream() - lx :sync() - local i = lx.src:match ("^#.-\n()", lx.i) - if i then - lx.i = i - lx.column_offset = i - lx.line = lx.line and lx.line + 1 or 1 - end - end - - local function chunk (lx) - if lx:peek().tag == 'Eof' then - return { } -- handle empty files - else - M.skip_initial_sharp_comment (lx) - local chunk = M.block (lx) - if lx:peek().tag ~= "Eof" then - gg.parse_error(lx, "End-of-file expected") - end - return chunk - end - end - - -- chunk is wrapped in a sequence so that it has a "transformer" field. - M.chunk = gg.sequence { chunk, builder = unpack } - - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/stat.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/stat.lua deleted file mode 100644 index f7abb7b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/stat.lua +++ /dev/null @@ -1,283 +0,0 @@ ------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- --- Summary: metalua parser, statement/block parser. This is part of the --- definition of module [mlp]. --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- --- Exports API: --- * [mlp.stat()] --- * [mlp.block()] --- * [mlp.for_header()] --- -------------------------------------------------------------------------------- - -local lexer = require 'metalua.grammar.lexer' -local gg = require 'metalua.grammar.generator' - -local annot = require 'metalua.compiler.parser.annot.generator' - --------------------------------------------------------------------------------- --- List of all keywords that indicate the end of a statement block. Users are --- likely to extend this list when designing extensions. --------------------------------------------------------------------------------- - - -return function(M) - local _M = gg.future(M) - - M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" } - - -- FIXME: this must be handled from within GG!!! - -- FIXME: there's no :add method in the list anyway. Added by gg.list?! - function M.block_terminators :add(x) - if type (x) == "table" then for _, y in ipairs(x) do self :add (y) end - else table.insert (self, x) end - end - - ---------------------------------------------------------------------------- - -- list of statements, possibly followed by semicolons - ---------------------------------------------------------------------------- - M.block = gg.list { - name = "statements block", - terminators = M.block_terminators, - primary = function (lx) - -- FIXME use gg.optkeyword() - local x = M.stat (lx) - if lx:is_keyword (lx:peek(), ";") then lx:next() end - return x - end } - - ---------------------------------------------------------------------------- - -- Helper function for "return " parsing. - -- Called when parsing return statements. - -- The specific test for initial ";" is because it's not a block terminator, - -- so without it gg.list would choke on "return ;" statements. - -- We don't make a modified copy of block_terminators because this list - -- is sometimes modified at runtime, and the return parser would get out of - -- sync if it was relying on a copy. - ---------------------------------------------------------------------------- - local return_expr_list_parser = gg.multisequence{ - { ";" , builder = function() return { } end }, - default = gg.list { - _M.expr, separators = ",", terminators = M.block_terminators } } - - - local for_vars_list = gg.list{ - name = "for variables list", - primary = _M.id, - separators = ",", - terminators = "in" } - - ---------------------------------------------------------------------------- - -- for header, between [for] and [do] (exclusive). - -- Return the `Forxxx{...} AST, without the body element (the last one). - ---------------------------------------------------------------------------- - function M.for_header (lx) - local vars = M.id_list(lx) - if lx :is_keyword (lx:peek(), "=") then - if #vars ~= 1 then - gg.parse_error (lx, "numeric for only accepts one variable") - end - lx:next() -- skip "=" - local exprs = M.expr_list (lx) - if #exprs < 2 or #exprs > 3 then - gg.parse_error (lx, "numeric for requires 2 or 3 boundaries") - end - return { tag="Fornum", vars[1], unpack (exprs) } - else - if not lx :is_keyword (lx :next(), "in") then - gg.parse_error (lx, '"=" or "in" expected in for loop') - end - local exprs = M.expr_list (lx) - return { tag="Forin", vars, exprs } - end - end - - ---------------------------------------------------------------------------- - -- Function def parser helper: id ( . id ) * - ---------------------------------------------------------------------------- - local function fn_builder (list) - local acc = list[1] - local first = acc.lineinfo.first - for i = 2, #list do - local index = M.id2string(list[i]) - local li = lexer.new_lineinfo(first, index.lineinfo.last) - acc = { tag="Index", acc, index, lineinfo=li } - end - return acc - end - local func_name = gg.list{ _M.id, separators = ".", builder = fn_builder } - - ---------------------------------------------------------------------------- - -- Function def parser helper: ( : id )? - ---------------------------------------------------------------------------- - local method_name = gg.onkeyword{ name = "method invocation", ":", _M.id, - transformers = { function(x) return x and x.tag=='Id' and M.id2string(x) end } } - - ---------------------------------------------------------------------------- - -- Function def builder - ---------------------------------------------------------------------------- - local function funcdef_builder(x) - local name, method, func = unpack(x) - if method then - name = { tag="Index", name, method, - lineinfo = { - first = name.lineinfo.first, - last = method.lineinfo.last } } - table.insert (func[1], 1, {tag="Id", "self"}) - end - local r = { tag="Set", {name}, {func} } - r[1].lineinfo = name.lineinfo - r[2].lineinfo = func.lineinfo - return r - end - - - ---------------------------------------------------------------------------- - -- if statement builder - ---------------------------------------------------------------------------- - local function if_builder (x) - local cond_block_pairs, else_block, r = x[1], x[2], {tag="If"} - local n_pairs = #cond_block_pairs - for i = 1, n_pairs do - local cond, block = unpack(cond_block_pairs[i]) - r[2*i-1], r[2*i] = cond, block - end - if else_block then table.insert(r, #r+1, else_block) end - return r - end - - -------------------------------------------------------------------------------- - -- produce a list of (expr,block) pairs - -------------------------------------------------------------------------------- - local elseifs_parser = gg.list { - gg.sequence { _M.expr, "then", _M.block , name='elseif parser' }, - separators = "elseif", - terminators = { "else", "end" } - } - - local annot_expr = gg.sequence { - _M.expr, - gg.onkeyword{ "#", gg.future(M, 'annot').tf }, - builder = function(x) - local e, a = unpack(x) - if a then return { tag='Annot', e, a } - else return e end - end } - - local annot_expr_list = gg.list { - primary = annot.opt(M, _M.expr, 'tf'), separators = ',' } - - ------------------------------------------------------------------------ - -- assignments and calls: statements that don't start with a keyword - ------------------------------------------------------------------------ - local function assign_or_call_stat_parser (lx) - local e = annot_expr_list (lx) - local a = lx:is_keyword(lx:peek()) - local op = a and M.assignments[a] - -- TODO: refactor annotations - if op then - --FIXME: check that [e] is a LHS - lx :next() - local annots - e, annots = annot.split(e) - local v = M.expr_list (lx) - if type(op)=="string" then return { tag=op, e, v, annots } - else return op (e, v) end - else - assert (#e > 0) - if #e > 1 then - gg.parse_error (lx, - "comma is not a valid statement separator; statement can be ".. - "separated by semicolons, or not separated at all") - elseif e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then - local typename - if e[1].tag == 'Id' then - typename = '("'..e[1][1]..'") is an identifier' - elseif e[1].tag == 'Op' then - typename = "is an arithmetic operation" - else typename = "is of type '"..(e[1].tag or "").."'" end - gg.parse_error (lx, - "This expression %s; ".. - "a statement was expected, and only function and method call ".. - "expressions can be used as statements", typename); - end - return e[1] - end - end - - M.local_stat_parser = gg.multisequence{ - -- local function - { "function", _M.id, _M.func_val, builder = - function(x) - local vars = { x[1], lineinfo = x[1].lineinfo } - local vals = { x[2], lineinfo = x[2].lineinfo } - return { tag="Localrec", vars, vals } - end }, - -- local ( = )? - default = gg.sequence{ - gg.list{ - primary = annot.opt(M, _M.id, 'tf'), - separators = ',' }, - gg.onkeyword{ "=", _M.expr_list }, - builder = function(x) - local annotated_left, right = unpack(x) - local left, annotations = annot.split(annotated_left) - return {tag="Local", left, right or { }, annotations } - end } } - - ------------------------------------------------------------------------ - -- statement - ------------------------------------------------------------------------ - M.stat = gg.multisequence { - name = "statement", - { "do", _M.block, "end", builder = - function (x) return { tag="Do", unpack (x[1]) } end }, - { "for", _M.for_header, "do", _M.block, "end", builder = - function (x) x[1][#x[1]+1] = x[2]; return x[1] end }, - { "function", func_name, method_name, _M.func_val, builder=funcdef_builder }, - { "while", _M.expr, "do", _M.block, "end", builder = "While" }, - { "repeat", _M.block, "until", _M.expr, builder = "Repeat" }, - { "local", _M.local_stat_parser, builder = unpack }, - { "return", return_expr_list_parser, builder = - function(x) x[1].tag='Return'; return x[1] end }, - { "goto", _M.id, builder = - function(x) x[1].tag='Goto'; return x[1] end }, - { "::", _M.id, "::", builder = - function(x) x[1].tag='Label'; return x[1] end }, - { "break", builder = function() return { tag="Break" } end }, - { "-{", gg.future(M, 'meta').splice_content, "}", builder = unpack }, - { "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", M.block }, "end", - builder = if_builder }, - default = assign_or_call_stat_parser } - - M.assignments = { - ["="] = "Set" - } - - function M.assignments:add(k, v) self[k] = v end - - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/table.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/table.lua deleted file mode 100644 index 11102d9..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/compiler/parser/table.lua +++ /dev/null @@ -1,77 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Exported API: --- * [M.table_bracket_field()] --- * [M.table_field()] --- * [M.table_content()] --- * [M.table()] --- --- KNOWN BUG: doesn't handle final ";" or "," before final "}" --- --------------------------------------------------------------------------------- - -local gg = require 'metalua.grammar.generator' - -return function(M) - - M.table = { } - local _table = gg.future(M.table) - local _expr = gg.future(M).expr - - -------------------------------------------------------------------------------- - -- `[key] = value` table field definition - -------------------------------------------------------------------------------- - M.table.bracket_pair = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" } - - -------------------------------------------------------------------------------- - -- table element parser: list value, `id = value` pair or `[value] = value` pair. - -------------------------------------------------------------------------------- - function M.table.element (lx) - if lx :is_keyword (lx :peek(), "[") then return M.table.bracket_pair(lx) end - local e = M.expr (lx) - if not lx :is_keyword (lx :peek(), "=") then return e end - lx :next(); -- skip the "=" - local key = M.id2string(e) -- will fail on non-identifiers - local val = M.expr(lx) - local r = { tag="Pair", key, val } - r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last } - return r - end - - ----------------------------------------------------------------------------- - -- table constructor, without enclosing braces; returns a full table object - ----------------------------------------------------------------------------- - M.table.content = gg.list { - -- eta expansion to allow patching the element definition - primary = _table.element, - separators = { ",", ";" }, - terminators = "}", - builder = "Table" } - - -------------------------------------------------------------------------------- - -- complete table constructor including [{...}] - -------------------------------------------------------------------------------- - -- TODO beware, stat and expr use only table.content, this can't be patched. - M.table.table = gg.sequence{ "{", _table.content, "}", builder = unpack } - - return M -end \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/generator.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/generator.lua deleted file mode 100644 index 4633c6e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/generator.lua +++ /dev/null @@ -1,832 +0,0 @@ --------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- --------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Summary: parser generator. Collection of higher order functors, --- which allow to build and combine parsers. Relies on a lexer --- that supports the same API as the one exposed in mll.lua. --- --------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- --- --- Exported API: --- --- Parser generators: --- * [gg.sequence()] --- * [gg.multisequence()] --- * [gg.expr()] --- * [gg.list()] --- * [gg.onkeyword()] --- * [gg.optkeyword()] --- --- Other functions: --- * [gg.parse_error()] --- * [gg.make_parser()] --- * [gg.is_parser()] --- --------------------------------------------------------------------------------- - -local M = { } - -local lexer = require 'metalua.grammar.lexer' - --------------------------------------------------------------------------------- --- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier. --- The main purpose is to avoid variable capture in macros. --- --- If a string is passed as an argument, theis string will be part of the --- id name (helpful for macro debugging) --------------------------------------------------------------------------------- -local gensymidx = 0 - -function M.gensym (arg) - gensymidx = gensymidx + 1 - return { tag="Id", string.format(".%i.%s", gensymidx, arg or "")} -end - - -------------------------------------------------------------------------------- --- parser metatable, which maps __call to method parse, and adds some --- error tracing boilerplate. -------------------------------------------------------------------------------- -local parser_metatable = { } - -function parser_metatable :__call (lx, ...) - return self :parse (lx, ...) -end - -------------------------------------------------------------------------------- --- Turn a table into a parser, mainly by setting the metatable. -------------------------------------------------------------------------------- -function M.make_parser(kind, p) - p.kind = kind - if not p.transformers then p.transformers = { } end - function p.transformers:add (x) - table.insert (self, x) - end - setmetatable (p, parser_metatable) - return p -end - -------------------------------------------------------------------------------- --- Return true iff [x] is a parser. --- If it's a gg-generated parser, return the name of its kind. -------------------------------------------------------------------------------- -function M.is_parser (x) - return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind -end - -------------------------------------------------------------------------------- --- Parse a sequence, without applying builder nor transformers. -------------------------------------------------------------------------------- -local function raw_parse_sequence (lx, p) - local r = { } - for i=1, #p do - local e=p[i] - if type(e) == "string" then - local kw = lx :next() - if not lx :is_keyword (kw, e) then - M.parse_error( - lx, "A keyword was expected, probably `%s'.", e) - end - elseif M.is_parser (e) then - table.insert (r, e(lx)) - else -- Invalid parser definition, this is *not* a parsing error - error(string.format( - "Sequence `%s': element #%i is neither a string nor a parser: %s", - p.name, i, table.tostring(e))) - end - end - return r -end - -------------------------------------------------------------------------------- --- Parse a multisequence, without applying multisequence transformers. --- The sequences are completely parsed. -------------------------------------------------------------------------------- -local function raw_parse_multisequence (lx, sequence_table, default) - local seq_parser = sequence_table[lx:is_keyword(lx:peek())] - if seq_parser then return seq_parser (lx) - elseif default then return default (lx) - else return false end -end - -------------------------------------------------------------------------------- --- Applies all transformers listed in parser on ast. -------------------------------------------------------------------------------- -local function transform (ast, parser, fli, lli) - if parser.transformers then - for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end - end - if type(ast) == 'table' then - local ali = ast.lineinfo - if not ali or ali.first~=fli or ali.last~=lli then - ast.lineinfo = lexer.new_lineinfo(fli, lli) - end - end - return ast -end - -------------------------------------------------------------------------------- --- Generate a tracable parsing error (not implemented yet) -------------------------------------------------------------------------------- -function M.parse_error(lx, fmt, ...) - local li = lx:lineinfo_left() - local file, line, column, offset, positions - if li then - file, line, column, offset = li.source, li.line, li.column, li.offset - positions = { first = li, last = li } - else - line, column, offset = -1, -1, -1 - end - - local msg = string.format("line %i, char %i: "..fmt, line, column, ...) - if file and file~='?' then msg = "file "..file..", "..msg end - - local src = lx.src - if offset>0 and src then - local i, j = offset, offset - while src:sub(i,i) ~= '\n' and i>=0 do i=i-1 end - while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end - local srcline = src:sub (i+1, j-1) - local idx = string.rep (" ", column).."^" - msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx) - end - --lx :kill() - error(msg) -end - -------------------------------------------------------------------------------- --- --- Sequence parser generator --- -------------------------------------------------------------------------------- --- Input fields: --- --- * [builder]: how to build an AST out of sequence parts. let [x] be the list --- of subparser results (keywords are simply omitted). [builder] can be: --- - [nil], in which case the result of parsing is simply [x] --- - a string, which is then put as a tag on [x] --- - a function, which takes [x] as a parameter and returns an AST. --- --- * [name]: the name of the parser. Used for debug messages --- --- * [transformers]: a list of AST->AST functions, applied in order on ASTs --- returned by the parser. --- --- * Table-part entries corresponds to keywords (strings) and subparsers --- (function and callable objects). --- --- After creation, the following fields are added: --- * [parse] the parsing function lexer->AST --- * [kind] == "sequence" --- * [name] is set, if it wasn't in the input. --- -------------------------------------------------------------------------------- -function M.sequence (p) - M.make_parser ("sequence", p) - - ------------------------------------------------------------------- - -- Parsing method - ------------------------------------------------------------------- - function p:parse (lx) - - -- Raw parsing: - local fli = lx:lineinfo_right() - local seq = raw_parse_sequence (lx, self) - local lli = lx:lineinfo_left() - - -- Builder application: - local builder, tb = self.builder, type (self.builder) - if tb == "string" then seq.tag = builder - elseif tb == "function" or builder and builder.__call then seq = builder(seq) - elseif builder == nil then -- nothing - else error ("Invalid builder of type "..tb.." in sequence") end - seq = transform (seq, self, fli, lli) - assert (not seq or seq.lineinfo) - return seq - end - - ------------------------------------------------------------------- - -- Construction - ------------------------------------------------------------------- - -- Try to build a proper name - if p.name then - -- don't touch existing name - elseif type(p[1])=="string" then -- find name based on 1st keyword - if #p==1 then p.name=p[1] - elseif type(p[#p])=="string" then - p.name = p[1] .. " ... " .. p[#p] - else p.name = p[1] .. " ..." end - else -- can't find a decent name - p.name = "unnamed_sequence" - end - - return p -end -- - - -------------------------------------------------------------------------------- --- --- Multiple, keyword-driven, sequence parser generator --- -------------------------------------------------------------------------------- --- in [p], useful fields are: --- --- * [transformers]: as usual --- --- * [name]: as usual --- --- * Table-part entries must be sequence parsers, or tables which can --- be turned into a sequence parser by [gg.sequence]. These --- sequences must start with a keyword, and this initial keyword --- must be different for each sequence. The table-part entries will --- be removed after [gg.multisequence] returns. --- --- * [default]: the parser to run if the next keyword in the lexer is --- none of the registered initial keywords. If there's no default --- parser and no suitable initial keyword, the multisequence parser --- simply returns [false]. --- --- After creation, the following fields are added: --- --- * [parse] the parsing function lexer->AST --- --- * [sequences] the table of sequences, indexed by initial keywords. --- --- * [add] method takes a sequence parser or a config table for --- [gg.sequence], and adds/replaces the corresponding sequence --- parser. If the keyword was already used, the former sequence is --- removed and a warning is issued. --- --- * [get] method returns a sequence by its initial keyword --- --- * [kind] == "multisequence" --- -------------------------------------------------------------------------------- -function M.multisequence (p) - M.make_parser ("multisequence", p) - - ------------------------------------------------------------------- - -- Add a sequence (might be just a config table for [gg.sequence]) - ------------------------------------------------------------------- - function p :add (s) - -- compile if necessary: - local keyword = type(s)=='table' and s[1] - if type(s)=='table' and not M.is_parser(s) then M.sequence(s) end - if M.is_parser(s)~='sequence' or type(keyword)~='string' then - if self.default then -- two defaults - error ("In a multisequence parser, all but one sequences ".. - "must start with a keyword") - else self.default = s end -- first default - else - if self.sequences[keyword] then -- duplicate keyword - -- TODO: warn that initial keyword `keyword` is overloaded in multiseq - end - self.sequences[keyword] = s - end - end -- - - ------------------------------------------------------------------- - -- Get the sequence starting with this keyword. [kw :: string] - ------------------------------------------------------------------- - function p :get (kw) return self.sequences [kw] end - - ------------------------------------------------------------------- - -- Remove the sequence starting with keyword [kw :: string] - ------------------------------------------------------------------- - function p :del (kw) - if not self.sequences[kw] then - -- TODO: warn that we try to delete a non-existent entry - end - local removed = self.sequences[kw] - self.sequences[kw] = nil - return removed - end - - ------------------------------------------------------------------- - -- Parsing method - ------------------------------------------------------------------- - function p :parse (lx) - local fli = lx:lineinfo_right() - local x = raw_parse_multisequence (lx, self.sequences, self.default) - local lli = lx:lineinfo_left() - return transform (x, self, fli, lli) - end - - ------------------------------------------------------------------- - -- Construction - ------------------------------------------------------------------- - -- Register the sequences passed to the constructor. They're going - -- from the array part of the parser to the hash part of field - -- [sequences] - p.sequences = { } - for i=1, #p do p :add (p[i]); p[i] = nil end - - -- FIXME: why is this commented out? - --if p.default and not is_parser(p.default) then sequence(p.default) end - return p -end -- - - -------------------------------------------------------------------------------- --- --- Expression parser generator --- -------------------------------------------------------------------------------- --- --- Expression configuration relies on three tables: [prefix], [infix] --- and [suffix]. Moreover, the primary parser can be replaced by a --- table: in this case the [primary] table will be passed to --- [gg.multisequence] to create a parser. --- --- Each of these tables is a modified multisequence parser: the --- differences with respect to regular multisequence config tables are: --- --- * the builder takes specific parameters: --- - for [prefix], it takes the result of the prefix sequence parser, --- and the prefixed expression --- - for [infix], it takes the left-hand-side expression, the results --- of the infix sequence parser, and the right-hand-side expression. --- - for [suffix], it takes the suffixed expression, and the result --- of the suffix sequence parser. --- --- * the default field is a list, with parameters: --- - [parser] the raw parsing function --- - [transformers], as usual --- - [prec], the operator's precedence --- - [assoc] for [infix] table, the operator's associativity, which --- can be "left", "right" or "flat" (default to left) --- --- In [p], useful fields are: --- * [transformers]: as usual --- * [name]: as usual --- * [primary]: the atomic expression parser, or a multisequence config --- table (mandatory) --- * [prefix]: prefix operators config table, see above. --- * [infix]: infix operators config table, see above. --- * [suffix]: suffix operators config table, see above. --- --- After creation, these fields are added: --- * [kind] == "expr" --- * [parse] as usual --- * each table is turned into a multisequence, and therefore has an --- [add] method --- -------------------------------------------------------------------------------- -function M.expr (p) - M.make_parser ("expr", p) - - ------------------------------------------------------------------- - -- parser method. - -- In addition to the lexer, it takes an optional precedence: - -- it won't read expressions whose precedence is lower or equal - -- to [prec]. - ------------------------------------------------------------------- - function p :parse (lx, prec) - prec = prec or 0 - - ------------------------------------------------------ - -- Extract the right parser and the corresponding - -- options table, for (pre|in|suff)fix operators. - -- Options include prec, assoc, transformers. - ------------------------------------------------------ - local function get_parser_info (tab) - local p2 = tab :get (lx :is_keyword (lx :peek())) - if p2 then -- keyword-based sequence found - local function parser(lx) return raw_parse_sequence(lx, p2) end - return parser, p2 - else -- Got to use the default parser - local d = tab.default - if d then return d.parse or d.parser, d - else return false, false end - end - end - - ------------------------------------------------------ - -- Look for a prefix sequence. Multiple prefixes are - -- handled through the recursive [p.parse] call. - -- Notice the double-transform: one for the primary - -- expr, and one for the one with the prefix op. - ------------------------------------------------------ - local function handle_prefix () - local fli = lx :lineinfo_right() - local p2_func, p2 = get_parser_info (self.prefix) - local op = p2_func and p2_func (lx) - if op then -- Keyword-based sequence found - local ili = lx :lineinfo_right() -- Intermediate LineInfo - local e = p2.builder (op, self :parse (lx, p2.prec)) - local lli = lx :lineinfo_left() - return transform (transform (e, p2, ili, lli), self, fli, lli) - else -- No prefix found, get a primary expression - local e = self.primary(lx) - local lli = lx :lineinfo_left() - return transform (e, self, fli, lli) - end - end -- - - ------------------------------------------------------ - -- Look for an infix sequence+right-hand-side operand. - -- Return the whole binary expression result, - -- or false if no operator was found. - ------------------------------------------------------ - local function handle_infix (e) - local p2_func, p2 = get_parser_info (self.infix) - if not p2 then return false end - - ----------------------------------------- - -- Handle flattening operators: gather all operands - -- of the series in [list]; when a different operator - -- is found, stop, build from [list], [transform] and - -- return. - ----------------------------------------- - if (not p2.prec or p2.prec>prec) and p2.assoc=="flat" then - local fli = lx:lineinfo_right() - local pflat, list = p2, { e } - repeat - local op = p2_func(lx) - if not op then break end - table.insert (list, self:parse (lx, p2.prec)) - local _ -- We only care about checking that p2==pflat - _, p2 = get_parser_info (self.infix) - until p2 ~= pflat - local e2 = pflat.builder (list) - local lli = lx:lineinfo_left() - return transform (transform (e2, pflat, fli, lli), self, fli, lli) - - ----------------------------------------- - -- Handle regular infix operators: [e] the LHS is known, - -- just gather the operator and [e2] the RHS. - -- Result goes in [e3]. - ----------------------------------------- - elseif p2.prec and p2.prec>prec or - p2.prec==prec and p2.assoc=="right" then - local fli = e.lineinfo.first -- lx:lineinfo_right() - local op = p2_func(lx) - if not op then return false end - local e2 = self:parse (lx, p2.prec) - local e3 = p2.builder (e, op, e2) - local lli = lx:lineinfo_left() - return transform (transform (e3, p2, fli, lli), self, fli, lli) - - ----------------------------------------- - -- Check for non-associative operators, and complain if applicable. - ----------------------------------------- - elseif p2.assoc=="none" and p2.prec==prec then - M.parse_error (lx, "non-associative operator!") - - ----------------------------------------- - -- No infix operator suitable at that precedence - ----------------------------------------- - else return false end - - end -- - - ------------------------------------------------------ - -- Look for a suffix sequence. - -- Return the result of suffix operator on [e], - -- or false if no operator was found. - ------------------------------------------------------ - local function handle_suffix (e) - -- FIXME bad fli, must take e.lineinfo.first - local p2_func, p2 = get_parser_info (self.suffix) - if not p2 then return false end - if not p2.prec or p2.prec>=prec then - --local fli = lx:lineinfo_right() - local fli = e.lineinfo.first - local op = p2_func(lx) - if not op then return false end - local lli = lx:lineinfo_left() - e = p2.builder (e, op) - e = transform (transform (e, p2, fli, lli), self, fli, lli) - return e - end - return false - end -- - - ------------------------------------------------------ - -- Parser body: read suffix and (infix+operand) - -- extensions as long as we're able to fetch more at - -- this precedence level. - ------------------------------------------------------ - local e = handle_prefix() - repeat - local x = handle_suffix (e); e = x or e - local y = handle_infix (e); e = y or e - until not (x or y) - - -- No transform: it already happened in operators handling - return e - end -- - - ------------------------------------------------------------------- - -- Construction - ------------------------------------------------------------------- - if not p.primary then p.primary=p[1]; p[1]=nil end - for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do - if not p[t] then p[t] = { } end - if not M.is_parser(p[t]) then M.multisequence(p[t]) end - end - function p:add(...) return self.primary:add(...) end - return p -end -- - - -------------------------------------------------------------------------------- --- --- List parser generator --- -------------------------------------------------------------------------------- --- In [p], the following fields can be provided in input: --- --- * [builder]: takes list of subparser results, returns AST --- * [transformers]: as usual --- * [name]: as usual --- --- * [terminators]: list of strings representing the keywords which --- might mark the end of the list. When non-empty, the list is --- allowed to be empty. A string is treated as a single-element --- table, whose element is that string, e.g. ["do"] is the same as --- [{"do"}]. --- --- * [separators]: list of strings representing the keywords which can --- separate elements of the list. When non-empty, one of these --- keyword has to be found between each element. Lack of a separator --- indicates the end of the list. A string is treated as a --- single-element table, whose element is that string, e.g. ["do"] --- is the same as [{"do"}]. If [terminators] is empty/nil, then --- [separators] has to be non-empty. --- --- After creation, the following fields are added: --- * [parse] the parsing function lexer->AST --- * [kind] == "list" --- -------------------------------------------------------------------------------- -function M.list (p) - M.make_parser ("list", p) - - ------------------------------------------------------------------- - -- Parsing method - ------------------------------------------------------------------- - function p :parse (lx) - - ------------------------------------------------------ - -- Used to quickly check whether there's a terminator - -- or a separator immediately ahead - ------------------------------------------------------ - local function peek_is_in (keywords) - return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end - - local x = { } - local fli = lx :lineinfo_right() - - -- if there's a terminator to start with, don't bother trying - local is_empty_list = self.terminators and (peek_is_in (self.terminators) or lx:peek().tag=="Eof") - if not is_empty_list then - repeat - local item = self.primary(lx) - table.insert (x, item) -- read one element - until - -- There's a separator list specified, and next token isn't in it. - -- Otherwise, consume it with [lx:next()] - self.separators and not(peek_is_in (self.separators) and lx:next()) or - -- Terminator token ahead - peek_is_in (self.terminators) or - -- Last reason: end of file reached - lx:peek().tag=="Eof" - end - - local lli = lx:lineinfo_left() - - -- Apply the builder. It can be a string, or a callable value, - -- or simply nothing. - local b = self.builder - if b then - if type(b)=="string" then x.tag = b -- b is a string, use it as a tag - elseif type(b)=="function" then x=b(x) - else - local bmt = getmetatable(b) - if bmt and bmt.__call then x=b(x) end - end - end - return transform (x, self, fli, lli) - end -- - - ------------------------------------------------------------------- - -- Construction - ------------------------------------------------------------------- - if not p.primary then p.primary = p[1]; p[1] = nil end - if type(p.terminators) == "string" then p.terminators = { p.terminators } - elseif p.terminators and #p.terminators == 0 then p.terminators = nil end - if type(p.separators) == "string" then p.separators = { p.separators } - elseif p.separators and #p.separators == 0 then p.separators = nil end - - return p -end -- - - -------------------------------------------------------------------------------- --- --- Keyword-conditioned parser generator --- -------------------------------------------------------------------------------- --- --- Only apply a parser if a given keyword is found. The result of --- [gg.onkeyword] parser is the result of the subparser (modulo --- [transformers] applications). --- --- lineinfo: the keyword is *not* included in the boundaries of the --- resulting lineinfo. A review of all usages of gg.onkeyword() in the --- implementation of metalua has shown that it was the appropriate choice --- in every case. --- --- Input fields: --- --- * [name]: as usual --- --- * [transformers]: as usual --- --- * [peek]: if non-nil, the conditioning keyword is left in the lexeme --- stream instead of being consumed. --- --- * [primary]: the subparser. --- --- * [keywords]: list of strings representing triggering keywords. --- --- * Table-part entries can contain strings, and/or exactly one parser. --- Strings are put in [keywords], and the parser is put in [primary]. --- --- After the call, the following fields will be set: --- --- * [parse] the parsing method --- * [kind] == "onkeyword" --- * [primary] --- * [keywords] --- -------------------------------------------------------------------------------- -function M.onkeyword (p) - M.make_parser ("onkeyword", p) - - ------------------------------------------------------------------- - -- Parsing method - ------------------------------------------------------------------- - function p :parse (lx) - if lx :is_keyword (lx:peek(), unpack(self.keywords)) then - local fli = lx:lineinfo_right() - if not self.peek then lx:next() end - local content = self.primary (lx) - local lli = lx:lineinfo_left() - local li = content.lineinfo or { } - fli, lli = li.first or fli, li.last or lli - return transform (content, p, fli, lli) - else return false end - end - - ------------------------------------------------------------------- - -- Construction - ------------------------------------------------------------------- - if not p.keywords then p.keywords = { } end - for _, x in ipairs(p) do - if type(x)=="string" then table.insert (p.keywords, x) - else assert (not p.primary and M.is_parser (x)); p.primary = x end - end - assert (next (p.keywords), "Missing trigger keyword in gg.onkeyword") - assert (p.primary, 'no primary parser in gg.onkeyword') - return p -end -- - - -------------------------------------------------------------------------------- --- --- Optional keyword consummer pseudo-parser generator --- -------------------------------------------------------------------------------- --- --- This doesn't return a real parser, just a function. That function parses --- one of the keywords passed as parameters, and returns it. It returns --- [false] if no matching keyword is found. --- --- Notice that tokens returned by lexer already carry lineinfo, therefore --- there's no need to add them, as done usually through transform() calls. -------------------------------------------------------------------------------- -function M.optkeyword (...) - local args = {...} - if type (args[1]) == "table" then - assert (#args == 1) - args = args[1] - end - for _, v in ipairs(args) do assert (type(v)=="string") end - return function (lx) - local x = lx:is_keyword (lx:peek(), unpack (args)) - if x then lx:next(); return x - else return false end - end -end - - -------------------------------------------------------------------------------- --- --- Run a parser with a special lexer --- -------------------------------------------------------------------------------- --- --- This doesn't return a real parser, just a function. --- First argument is the lexer class to be used with the parser, --- 2nd is the parser itself. --- The resulting parser returns whatever the argument parser does. --- -------------------------------------------------------------------------------- -function M.with_lexer(new_lexer, parser) - - ------------------------------------------------------------------- - -- Most gg functions take their parameters in a table, so it's - -- better to silently accept when with_lexer{ } is called with - -- its arguments in a list: - ------------------------------------------------------------------- - if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then - return M.with_lexer(unpack(new_lexer)) - end - - ------------------------------------------------------------------- - -- Save the current lexer, switch it for the new one, run the parser, - -- restore the previous lexer, even if the parser caused an error. - ------------------------------------------------------------------- - return function (lx) - local old_lexer = getmetatable(lx) - lx:sync() - setmetatable(lx, new_lexer) - local status, result = pcall(parser, lx) - lx:sync() - setmetatable(lx, old_lexer) - if status then return result else error(result) end - end -end - --------------------------------------------------------------------------------- --- --- Make sure a parser is used and returns successfully. --- --------------------------------------------------------------------------------- -function M.nonempty(primary) - local p = M.make_parser('non-empty list', { primary = primary, name=primary.name }) - function p :parse (lx) - local fli = lx:lineinfo_right() - local content = self.primary (lx) - local lli = lx:lineinfo_left() - local li = content.lineinfo or { } - fli, lli = li.first or fli, li.last or lli - if #content == 0 then - M.parse_error (lx, "`%s' must not be empty.", self.name or "list") - else - return transform (content, self, fli, lli) - end - end - return p -end - -local FUTURE_MT = { } -function FUTURE_MT:__tostring() return "" end -function FUTURE_MT:__newindex(key, value) error "don't write in futures" end -function FUTURE_MT :__index (parser_name) - return function(...) - local p, m = rawget(self, '__path'), self.__module - if p then for _, name in ipairs(p) do - m=rawget(m, name) - if not m then error ("Submodule '"..name.."' undefined") end - end end - local f = rawget(m, parser_name) - if not f then error ("Parser '"..parser_name.."' undefined") end - return f(...) - end -end - -function M.future(module, ...) - checks('table') - local path = ... and {...} - if path then for _, x in ipairs(path) do - assert(type(x)=='string', "Bad future arg") - end end - local self = { __module = module, - __path = path } - return setmetatable(self, FUTURE_MT) -end - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/lexer.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/lexer.lua deleted file mode 100644 index 8840ea8..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/grammar/lexer.lua +++ /dev/null @@ -1,678 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- -------------------------------------------------------------------------------- - -require 'checks' - -local M = { } - -local lexer = { alpha={ }, sym={ } } -lexer.__index=lexer -lexer.__type='lexer.stream' - -M.lexer = lexer - - -local debugf = function() end --- local debugf=printf - ----------------------------------------------------------------------- --- Some locale settings produce bad results, e.g. French locale --- expect float numbers to use commas instead of periods. --- TODO: change number parser into something loclae-independent, --- locales are nasty. ----------------------------------------------------------------------- -os.setlocale('C') - -local MT = { } - -M.metatables=MT - ----------------------------------------------------------------------- --- Create a new metatable, for a new class of objects. ----------------------------------------------------------------------- -local function new_metatable(name) - local mt = { __type = 'lexer.'..name }; - mt.__index = mt - MT[name] = mt -end - - ----------------------------------------------------------------------- --- Position: represent a point in a source file. ----------------------------------------------------------------------- -new_metatable 'position' - -local position_idx=1 - -function M.new_position(line, column, offset, source) - checks('number', 'number', 'number', 'string') - local id = position_idx; position_idx = position_idx+1 - return setmetatable({line=line, column=column, offset=offset, - source=source, id=id}, MT.position) -end - -function MT.position :__tostring() - return string.format("<%s%s|L%d|C%d|K%d>", - self.comments and "C|" or "", - self.source, self.line, self.column, self.offset) -end - - - ----------------------------------------------------------------------- --- Position factory: convert offsets into line/column/offset positions. ----------------------------------------------------------------------- -new_metatable 'position_factory' - -function M.new_position_factory(src, src_name) - -- assert(type(src)=='string') - -- assert(type(src_name)=='string') - local lines = { 1 } - for offset in src :gmatch '\n()' do table.insert(lines, offset) end - local max = #src+1 - table.insert(lines, max+1) -- +1 includes Eof - return setmetatable({ src_name=src_name, line2offset=lines, max=max }, - MT.position_factory) -end - -function MT.position_factory :get_position (offset) - -- assert(type(offset)=='number') - assert(offset<=self.max) - local line2offset = self.line2offset - local left = self.last_left or 1 - if offset", - fli.comments and "C|" or "", - fli.source, line, column, offset, - lli.comments and "|C" or "") -end - ----------------------------------------------------------------------- --- Token: atomic Lua language element, with a category, a content, --- and some lineinfo relating it to its original source. ----------------------------------------------------------------------- -new_metatable 'token' - -function M.new_token(tag, content, lineinfo) - --printf("TOKEN `%s{ %q, lineinfo = %s} boundaries %d, %d", - -- tag, content, tostring(lineinfo), lineinfo.first.id, lineinfo.last.id) - return setmetatable({tag=tag, lineinfo=lineinfo, content}, MT.token) -end - -function MT.token :__tostring() - --return string.format("`%s{ %q, %s }", self.tag, self[1], tostring(self.lineinfo)) - return string.format("`%s %q", self.tag, self[1]) -end - - ----------------------------------------------------------------------- --- Comment: series of comment blocks with associated lineinfo. --- To be attached to the tokens just before and just after them. ----------------------------------------------------------------------- -new_metatable 'comment' - -function M.new_comment(lines) - local first = lines[1].lineinfo.first - local last = lines[#lines].lineinfo.last - local lineinfo = M.new_lineinfo(first, last) - return setmetatable({lineinfo=lineinfo, unpack(lines)}, MT.comment) -end - -function MT.comment :text() - local last_line = self[1].lineinfo.last.line - local acc = { } - for i, line in ipairs(self) do - local nreturns = line.lineinfo.first.line - last_line - table.insert(acc, ("\n"):rep(nreturns)) - table.insert(acc, line[1]) - end - return table.concat(acc) -end - -function M.new_comment_line(text, lineinfo, nequals) - checks('string', 'lexer.lineinfo', '?number') - return { lineinfo = lineinfo, text, nequals } -end - - - ----------------------------------------------------------------------- --- Patterns used by [lexer :extract] to decompose the raw string into --- correctly tagged tokens. ----------------------------------------------------------------------- -lexer.patterns = { - spaces = "^[ \r\n\t]*()", - short_comment = "^%-%-([^\n]*)\n?()", - --final_short_comment = "^%-%-([^\n]*)()$", - long_comment = "^%-%-%[(=*)%[\n?(.-)%]%1%]()", - long_string = "^%[(=*)%[\n?(.-)%]%1%]()", - number_longint = "^%d+[uU]?[lL][lL]()", - number_longint_hex = "^%x+[uU]?[lL][lL]()", - number_mantissa = { "^%d+%.?%d*()", "^%d*%.%d+()" }, - number_mantissa_hex = { "^%x+%.?%x*()", "^%x*%.%x+()" }, --Lua5.1 and Lua5.2 - number_exponent = "^[eE][%+%-]?%d+()", - number_exponent_hex = "^[pP][%+%-]?%d+()", --Lua5.2 - number_hex = "^0[xX]()", - number_imaginary = "^[iI]()", - word = "^([%a_][%w_]*)()", -} - ----------------------------------------------------------------------- --- unescape a whole string, applying [unesc_digits] and --- [unesc_letter] as many times as required. ----------------------------------------------------------------------- -local function unescape_string (s) - - -- Turn the digits of an escape sequence into the corresponding - -- character, e.g. [unesc_digits("123") == string.char(123)]. - local function unesc_digits (backslashes, digits) - if #backslashes%2==0 then - -- Even number of backslashes, they escape each other, not the digits. - -- Return them so that unesc_letter() can treat them - return backslashes..digits - else - -- Remove the odd backslash, which escapes the number sequence. - -- The rest will be returned and parsed by unesc_letter() - backslashes = backslashes :sub (1,-2) - end - local k, j, i = digits :reverse() :byte(1, 3) - local z = string.byte "0" - local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z - if code > 255 then - error ("Illegal escape sequence '\\"..digits.. - "' in string: ASCII codes must be in [0..255]") - end - local c = string.char (code) - if c == '\\' then c = '\\\\' end -- parsed by unesc_letter (test: "\092b" --> "\\b") - return backslashes..c - end - - -- Turn hex digits of escape sequence into char. - local function unesc_hex(backslashes, digits) - if #backslashes%2==0 then - return backslashes..'x'..digits - else - backslashes = backslashes :sub (1,-2) - end - local c = string.char(tonumber(digits,16)) - if c == '\\' then c = '\\\\' end -- parsed by unesc_letter (test: "\x5cb" --> "\\b") - return backslashes..c - end - - -- Handle Lua 5.2 \z sequences - local function unesc_z(backslashes, more) - if #backslashes%2==0 then - return backslashes..more - else - return backslashes :sub (1,-2) - end - end - - -- Take a letter [x], and returns the character represented by the - -- sequence ['\\'..x], e.g. [unesc_letter "n" == "\n"]. - local function unesc_letter(x) - local t = { - a = "\a", b = "\b", f = "\f", - n = "\n", r = "\r", t = "\t", v = "\v", - ["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" } - return t[x] or x - end - - s = s: gsub ("(\\+)(z%s*)", unesc_z) -- Lua 5.2 - s = s: gsub ("(\\+)([0-9][0-9]?[0-9]?)", unesc_digits) - s = s: gsub ("(\\+)x([0-9a-fA-F][0-9a-fA-F])", unesc_hex) -- Lua 5.2 - s = s: gsub ("\\(%D)",unesc_letter) - return s -end - -lexer.extractors = { - "extract_long_comment", "extract_short_comment", - "extract_short_string", "extract_word", "extract_number", - "extract_long_string", "extract_symbol" } - - - ----------------------------------------------------------------------- --- Really extract next token from the raw string --- (and update the index). --- loc: offset of the position just after spaces and comments --- previous_i: offset in src before extraction began ----------------------------------------------------------------------- -function lexer :extract () - local attached_comments = { } - local function gen_token(...) - local token = M.new_token(...) - if #attached_comments>0 then -- attach previous comments to token - local comments = M.new_comment(attached_comments) - token.lineinfo.first.comments = comments - if self.lineinfo_last_extracted then - self.lineinfo_last_extracted.comments = comments - end - attached_comments = { } - end - token.lineinfo.first.facing = self.lineinfo_last_extracted - self.lineinfo_last_extracted.facing = assert(token.lineinfo.first) - self.lineinfo_last_extracted = assert(token.lineinfo.last) - return token - end - while true do -- loop until a non-comment token is found - - -- skip whitespaces - self.i = self.src:match (self.patterns.spaces, self.i) - if self.i>#self.src then - local fli = self.posfact :get_position (#self.src+1) - local lli = self.posfact :get_position (#self.src+1) -- ok? - local tok = gen_token("Eof", "eof", M.new_lineinfo(fli, lli)) - tok.lineinfo.last.facing = lli - return tok - end - local i_first = self.i -- loc = position after whitespaces - - -- try every extractor until a token is found - for _, extractor in ipairs(self.extractors) do - local tag, content, xtra = self [extractor] (self) - if tag then - local fli = self.posfact :get_position (i_first) - local lli = self.posfact :get_position (self.i-1) - local lineinfo = M.new_lineinfo(fli, lli) - if tag=='Comment' then - local prev_comment = attached_comments[#attached_comments] - if not xtra -- new comment is short - and prev_comment and not prev_comment[2] -- prev comment is short - and prev_comment.lineinfo.last.line+1==fli.line then -- adjascent lines - -- concat with previous comment - prev_comment[1] = prev_comment[1].."\n"..content -- TODO quadratic, BAD! - prev_comment.lineinfo.last = lli - else -- accumulate comment - local comment = M.new_comment_line(content, lineinfo, xtra) - table.insert(attached_comments, comment) - end - break -- back to skipping spaces - else -- not a comment: real token, then - return gen_token(tag, content, lineinfo) - end -- if token is a comment - end -- if token found - end -- for each extractor - end -- while token is a comment -end -- :extract() - - - - ----------------------------------------------------------------------- --- Extract a short comment. ----------------------------------------------------------------------- -function lexer :extract_short_comment() - -- TODO: handle final_short_comment - local content, j = self.src :match (self.patterns.short_comment, self.i) - if content then self.i=j; return 'Comment', content, nil end -end - ----------------------------------------------------------------------- --- Extract a long comment. ----------------------------------------------------------------------- -function lexer :extract_long_comment() - local equals, content, j = self.src:match (self.patterns.long_comment, self.i) - if j then self.i = j; return "Comment", content, #equals end -end - ----------------------------------------------------------------------- --- Extract a '...' or "..." short string. ----------------------------------------------------------------------- -function lexer :extract_short_string() - local k = self.src :sub (self.i,self.i) -- first char - if k~=[[']] and k~=[["]] then return end -- no match' - local i = self.i + 1 - local j = i - while true do - local x,y; x, j, y = self.src :match ("([\\\r\n"..k.."])()(.?)", j) -- next interesting char - if x == '\\' then - if y == 'z' then -- Lua 5.2 \z - j = self.src :match ("^%s*()", j+1) - else - j=j+1 -- escaped char - end - elseif x == k then break -- end of string - else - assert (not x or x=='\r' or x=='\n') - return nil, 'Unterminated string' - end - end - self.i = j - - return 'String', unescape_string (self.src :sub (i,j-2)) -end - ----------------------------------------------------------------------- --- Extract Id or Keyword. ----------------------------------------------------------------------- -function lexer :extract_word() - local word, j = self.src:match (self.patterns.word, self.i) - if word then - self.i = j - return (self.alpha [word] and 'Keyword' or 'Id'), word - end -end - ----------------------------------------------------------------------- --- Extract Number. ----------------------------------------------------------------------- -function lexer :extract_number() - local patt = self.patterns - local s = self.src - local j = s:match(patt.number_hex, self.i) - local hex = j ~= nil - local longint = hex and patt.number_longint_hex or patt.number_longint - local mantissa1 = hex and patt.number_mantissa_hex[1] or patt.number_mantissa[1] - local mantissa2 = hex and patt.number_mantissa_hex[2] or patt.number_mantissa[2] - local exponent = hex and patt.number_exponent_hex or patt.number_exponent - if not hex then j = self.i end - - local t = s:match(longint, j) - if t then - j = t - else - j = s:match(mantissa1, j) or s:match(mantissa2, j) - if not j then return end - j = s:match(exponent, j) or j - j = s:match(patt.number_imaginary, j) or j - end - - local str = self.src:sub (self.i, j-1) - self.i = j - -- Number found, interpret with tonumber() and return it - -- return str as the fallback when processing formats not supported by the current interpreter - return 'Number', (tonumber (str) or str) -end - ----------------------------------------------------------------------- --- Extract long string. ----------------------------------------------------------------------- -function lexer :extract_long_string() - local _, content, j = self.src :match (self.patterns.long_string, self.i) - if j then self.i = j; return 'String', content end -end - ----------------------------------------------------------------------- --- Extract symbol. ----------------------------------------------------------------------- -function lexer :extract_symbol() - local k = self.src:sub (self.i,self.i) - local symk = self.sym [k] -- symbols starting with `k` - if not symk then - self.i = self.i + 1 - return 'Keyword', k - end - for _, sym in pairs (symk) do - if sym == self.src:sub (self.i, self.i + #sym - 1) then - self.i = self.i + #sym - return 'Keyword', sym - end - end - self.i = self.i+1 - return 'Keyword', k -end - ----------------------------------------------------------------------- --- Add a keyword to the list of keywords recognized by the lexer. ----------------------------------------------------------------------- -function lexer :add (w, ...) - assert(not ..., "lexer :add() takes only one arg, although possibly a table") - if type (w) == "table" then - for _, x in ipairs (w) do self :add (x) end - else - if w:match (self.patterns.word .. "$") then self.alpha [w] = true - elseif w:match "^%p%p+$" then - local k = w:sub(1,1) - local list = self.sym [k] - if not list then list = { }; self.sym [k] = list end - table.insert (list, w) - elseif w:match "^%p$" then return - else error "Invalid keyword" end - end -end - ----------------------------------------------------------------------- --- Return the [n]th next token, without consuming it. --- [n] defaults to 1. If it goes pass the end of the stream, an EOF --- token is returned. ----------------------------------------------------------------------- -function lexer :peek (n) - if not n then n=1 end - if n > #self.peeked then - for i = #self.peeked+1, n do - self.peeked [i] = self :extract() - end - end - return self.peeked [n] -end - ----------------------------------------------------------------------- --- Return the [n]th next token, removing it as well as the 0..n-1 --- previous tokens. [n] defaults to 1. If it goes pass the end of the --- stream, an EOF token is returned. ----------------------------------------------------------------------- -function lexer :next (n) - n = n or 1 - self :peek (n) - local a - for i=1,n do - a = table.remove (self.peeked, 1) - -- TODO: is this used anywhere? I think not. a.lineinfo.last may be nil. - --self.lastline = a.lineinfo.last.line - end - self.lineinfo_last_consumed = a.lineinfo.last - return a -end - ----------------------------------------------------------------------- --- Returns an object which saves the stream's current state. ----------------------------------------------------------------------- --- FIXME there are more fields than that to save -function lexer :save () return { self.i; {unpack(self.peeked) } } end - ----------------------------------------------------------------------- --- Restore the stream's state, as saved by method [save]. ----------------------------------------------------------------------- --- FIXME there are more fields than that to restore -function lexer :restore (s) self.i=s[1]; self.peeked=s[2] end - ----------------------------------------------------------------------- --- Resynchronize: cancel any token in self.peeked, by emptying the --- list and resetting the indexes ----------------------------------------------------------------------- -function lexer :sync() - local p1 = self.peeked[1] - if p1 then - local li_first = p1.lineinfo.first - if li_first.comments then li_first=li_first.comments.lineinfo.first end - self.i = li_first.offset - self.column_offset = self.i - li_first.column - self.peeked = { } - self.attached_comments = p1.lineinfo.first.comments or { } - end -end - ----------------------------------------------------------------------- --- Take the source and offset of an old lexer. ----------------------------------------------------------------------- -function lexer :takeover(old) - self :sync(); old :sync() - for _, field in ipairs{ 'i', 'src', 'attached_comments', 'posfact' } do - self[field] = old[field] - end - return self -end - ----------------------------------------------------------------------- --- Return the current position in the sources. This position is between --- two tokens, and can be within a space / comment area, and therefore --- have a non-null width. :lineinfo_left() returns the beginning of the --- separation area, :lineinfo_right() returns the end of that area. --- --- ____ last consummed token ____ first unconsummed token --- / / --- XXXXX YYYYY --- \____ \____ --- :lineinfo_left() :lineinfo_right() ----------------------------------------------------------------------- -function lexer :lineinfo_right() - return self :peek(1).lineinfo.first -end - -function lexer :lineinfo_left() - return self.lineinfo_last_consumed -end - ----------------------------------------------------------------------- --- Create a new lexstream. ----------------------------------------------------------------------- -function lexer :newstream (src_or_stream, name) - name = name or "?" - if type(src_or_stream)=='table' then -- it's a stream - return setmetatable ({ }, self) :takeover (src_or_stream) - elseif type(src_or_stream)=='string' then -- it's a source string - local src = src_or_stream - local pos1 = M.new_position(1, 1, 1, name) - local stream = { - src_name = name; -- Name of the file - src = src; -- The source, as a single string - peeked = { }; -- Already peeked, but not discarded yet, tokens - i = 1; -- Character offset in src - attached_comments = { },-- comments accumulator - lineinfo_last_extracted = pos1, - lineinfo_last_consumed = pos1, - posfact = M.new_position_factory (src_or_stream, name) - } - setmetatable (stream, self) - - -- Skip initial sharp-bang for Unix scripts - -- FIXME: redundant with mlp.chunk() - if src and src :match "^#!" then - local endofline = src :find "\n" - stream.i = endofline and (endofline + 1) or #src - end - return stream - else - assert(false, ":newstream() takes a source string or a stream, not a ".. - type(src_or_stream)) - end -end - ----------------------------------------------------------------------- --- If there's no ... args, return the token a (whose truth value is --- true) if it's a `Keyword{ }, or nil. If there are ... args, they --- have to be strings. if the token a is a keyword, and it's content --- is one of the ... args, then returns it (it's truth value is --- true). If no a keyword or not in ..., return nil. ----------------------------------------------------------------------- -function lexer :is_keyword (a, ...) - if not a or a.tag ~= "Keyword" then return false end - local words = {...} - if #words == 0 then return a[1] end - for _, w in ipairs (words) do - if w == a[1] then return w end - end - return false -end - ----------------------------------------------------------------------- --- Cause an error if the next token isn't a keyword whose content --- is listed among ... args (which have to be strings). ----------------------------------------------------------------------- -function lexer :check (...) - local words = {...} - local a = self :next() - local function err () - error ("Got " .. tostring (a) .. - ", expected one of these keywords : '" .. - table.concat (words,"', '") .. "'") end - if not a or a.tag ~= "Keyword" then err () end - if #words == 0 then return a[1] end - for _, w in ipairs (words) do - if w == a[1] then return w end - end - err () -end - ----------------------------------------------------------------------- --- ----------------------------------------------------------------------- -function lexer :clone() - local alpha_clone, sym_clone = { }, { } - for word in pairs(self.alpha) do alpha_clone[word]=true end - for letter, list in pairs(self.sym) do sym_clone[letter] = { unpack(list) } end - local clone = { alpha=alpha_clone, sym=sym_clone } - setmetatable(clone, self) - clone.__index = clone - return clone -end - ----------------------------------------------------------------------- --- Cancel everything left in a lexer, all subsequent attempts at --- `:peek()` or `:next()` will return `Eof`. ----------------------------------------------------------------------- -function lexer :kill() - self.i = #self.src+1 - self.peeked = { } - self.attached_comments = { } - self.lineinfo_last = self.posfact :get_position (#self.src+1) -end - -return M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/pprint.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/pprint.lua deleted file mode 100644 index 73a842b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/metalua/pprint.lua +++ /dev/null @@ -1,295 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006-2013 Fabien Fleutot and others. --- --- All rights reserved. --- --- This program and the accompanying materials are made available --- under the terms of the Eclipse Public License v1.0 which --- accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- This program and the accompanying materials are also made available --- under the terms of the MIT public license which accompanies this --- distribution, and is available at http://www.lua.org/license.html --- --- Contributors: --- Fabien Fleutot - API and implementation --- ----------------------------------------------------------------------- - ----------------------------------------------------------------------- ----------------------------------------------------------------------- --- --- Lua objects pretty-printer --- ----------------------------------------------------------------------- ----------------------------------------------------------------------- - -local M = { } - -M.DEFAULT_CFG = { - hide_hash = false; -- Print the non-array part of tables? - metalua_tag = true; -- Use Metalua's backtick syntax sugar? - fix_indent = nil; -- If a number, number of indentation spaces; - -- If false, indent to the previous brace. - line_max = nil; -- If a number, tries to avoid making lines with - -- more than this number of chars. - initial_indent = 0; -- If a number, starts at this level of indentation - keywords = { }; -- Set of keywords which must not use Lua's field - -- shortcuts {["foo"]=...} -> {foo=...} -} - -local function valid_id(cfg, x) - if type(x) ~= "string" then return false end - if not x:match "^[a-zA-Z_][a-zA-Z0-9_]*$" then return false end - if cfg.keywords and cfg.keywords[x] then return false end - return true -end - -local __tostring_cache = setmetatable({ }, {__mode='k'}) - --- Retrieve the string produced by `__tostring` metamethod if present, --- return `false` otherwise. Cached in `__tostring_cache`. -local function __tostring(x) - local the_string = __tostring_cache[x] - if the_string~=nil then return the_string end - local mt = getmetatable(x) - if mt then - local __tostring = mt.__tostring - if __tostring then - the_string = __tostring(x) - __tostring_cache[x] = the_string - return the_string - end - end - if x~=nil then __tostring_cache[x] = false end -- nil is an illegal key - return false -end - -local xlen -- mutually recursive with `xlen_type` - -local xlen_cache = setmetatable({ }, {__mode='k'}) - --- Helpers for the `xlen` function -local xlen_type = { - ["nil"] = function ( ) return 3 end; - number = function (x) return #tostring(x) end; - boolean = function (x) return x and 4 or 5 end; - string = function (x) return #string.format("%q",x) end; -} - -function xlen_type.table (adt, cfg, nested) - local custom_string = __tostring(adt) - if custom_string then return #custom_string end - - -- Circular referenced objects are printed with the plain - -- `tostring` function in nested positions. - if nested [adt] then return #tostring(adt) end - nested [adt] = true - - local has_tag = cfg.metalua_tag and valid_id(cfg, adt.tag) - local alen = #adt - local has_arr = alen>0 - local has_hash = false - local x = 0 - - if not cfg.hide_hash then - -- first pass: count hash-part - for k, v in pairs(adt) do - if k=="tag" and has_tag then - -- this is the tag -> do nothing! - elseif type(k)=="number" and k<=alen and math.fmod(k,1)==0 and k>0 then - -- array-part pair -> do nothing! - else - has_hash = true - if valid_id(cfg, k) then x=x+#k - else x = x + xlen (k, cfg, nested) + 2 end -- count surrounding brackets - x = x + xlen (v, cfg, nested) + 5 -- count " = " and ", " - end - end - end - - for i = 1, alen do x = x + xlen (adt[i], nested) + 2 end -- count ", " - - nested[adt] = false -- No more nested calls - - if not (has_tag or has_arr or has_hash) then return 3 end - if has_tag then x=x+#adt.tag+1 end - if not (has_arr or has_hash) then return x end - if not has_hash and alen==1 and type(adt[1])~="table" then - return x-2 -- substract extraneous ", " - end - return x+2 -- count "{ " and " }", substract extraneous ", " -end - - --- Compute the number of chars it would require to display the table --- on a single line. Helps to decide whether some carriage returns are --- required. Since the size of each sub-table is required many times, --- it's cached in [xlen_cache]. -xlen = function (x, cfg, nested) - -- no need to compute length for 1-line prints - if not cfg.line_max then return 0 end - nested = nested or { } - if x==nil then return #"nil" end - local len = xlen_cache[x] - if len then return len end - local f = xlen_type[type(x)] - if not f then return #tostring(x) end - len = f (x, cfg, nested) - xlen_cache[x] = len - return len -end - -local function consider_newline(p, len) - if not p.cfg.line_max then return end - if p.current_offset + len <= p.cfg.line_max then return end - if p.indent < p.current_offset then - p:acc "\n"; p:acc ((" "):rep(p.indent)) - p.current_offset = p.indent - end -end - -local acc_value - -local acc_type = { - ["nil"] = function(p) p:acc("nil") end; - number = function(p, adt) p:acc (tostring (adt)) end; - string = function(p, adt) p:acc ((string.format ("%q", adt):gsub("\\\n", "\\n"))) end; - boolean = function(p, adt) p:acc (adt and "true" or "false") end } - --- Indentation: --- * if `cfg.fix_indent` is set to a number: --- * add this number of space for each level of depth --- * return to the line as soon as it flushes things further left --- * if not, tabulate to one space after the opening brace. --- * as a result, it never saves right-space to return before first element - -function acc_type.table(p, adt) - if p.nested[adt] then p:acc(tostring(adt)); return end - p.nested[adt] = true - - local has_tag = p.cfg.metalua_tag and valid_id(p.cfg, adt.tag) - local alen = #adt - local has_arr = alen>0 - local has_hash = false - - local previous_indent = p.indent - - if has_tag then p:acc("`"); p:acc(adt.tag) end - - local function indent(p) - if not p.cfg.fix_indent then p.indent = p.current_offset - else p.indent = p.indent + p.cfg.fix_indent end - end - - -- First pass: handle hash-part - if not p.cfg.hide_hash then - for k, v in pairs(adt) do - - if has_tag and k=='tag' then -- pass the 'tag' field - elseif type(k)=="number" and k<=alen and k>0 and math.fmod(k,1)==0 then - -- pass array-part keys (consecutive ints less than `#adt`) - else -- hash-part keys - if has_hash then p:acc ", " else -- 1st hash-part pair ever found - p:acc "{ "; indent(p) - end - - -- Determine whether a newline is required - local is_id, expected_len=valid_id(p.cfg, k) - if is_id then expected_len=#k+xlen(v, p.cfg, p.nested)+#" = , " - else expected_len = xlen(k, p.cfg, p.nested)+xlen(v, p.cfg, p.nested)+#"[] = , " end - consider_newline(p, expected_len) - - -- Print the key - if is_id then p:acc(k); p:acc " = " else - p:acc "["; acc_value (p, k); p:acc "] = " - end - - acc_value (p, v) -- Print the value - has_hash = true - end - end - end - - -- Now we know whether there's a hash-part, an array-part, and a tag. - -- Tag and hash-part are already printed if they're present. - if not has_tag and not has_hash and not has_arr then p:acc "{ }"; - elseif has_tag and not has_hash and not has_arr then -- nothing, tag already in acc - else - assert (has_hash or has_arr) -- special case { } already handled - local no_brace = false - if has_hash and has_arr then p:acc ", " - elseif has_tag and not has_hash and alen==1 and type(adt[1])~="table" then - -- No brace required; don't print "{", remember not to print "}" - p:acc (" "); acc_value (p, adt[1]) -- indent= indent+(cfg.fix_indent or 0)) - no_brace = true - elseif not has_hash then - -- Braces required, but not opened by hash-part handler yet - p:acc "{ "; indent(p) - end - - -- 2nd pass: array-part - if not no_brace and has_arr then - local expected_len = xlen(adt[1], p.cfg, p.nested) - consider_newline(p, expected_len) - acc_value(p, adt[1]) -- indent+(cfg.fix_indent or 0) - for i=2, alen do - p:acc ", "; - consider_newline(p, xlen(adt[i], p.cfg, p.nested)) - acc_value (p, adt[i]) --indent+(cfg.fix_indent or 0) - end - end - if not no_brace then p:acc " }" end - end - p.nested[adt] = false -- No more nested calls - p.indent = previous_indent -end - - -function acc_value(p, v) - local custom_string = __tostring(v) - if custom_string then p:acc(custom_string) else - local f = acc_type[type(v)] - if f then f(p, v) else p:acc(tostring(v)) end - end -end - - --- FIXME: new_indent seems to be always nil?!s detection --- FIXME: accumulator function should be configurable, --- so that print() doesn't need to bufferize the whole string --- before starting to print. -function M.tostring(t, cfg) - - cfg = cfg or M.DEFAULT_CFG or { } - - local p = { - cfg = cfg; - indent = 0; - current_offset = cfg.initial_indent or 0; - buffer = { }; - nested = { }; - acc = function(self, str) - table.insert(self.buffer, str) - self.current_offset = self.current_offset + #str - end; - } - acc_value(p, t) - return table.concat(p.buffer) -end - -function M.print(...) return print(M.tostring(...)) end -function M.sprintf(fmt, ...) - local args={...} - for i, v in pairs(args) do - local t=type(v) - if t=='table' then args[i]=M.tostring(v) - elseif t=='nil' then args[i]='nil' end - end - return string.format(fmt, unpack(args)) -end - -function M.printf(...) print(M.sprintf(...)) end - -return M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mime.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mime.lua deleted file mode 100644 index 642cd9c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mime.lua +++ /dev/null @@ -1,90 +0,0 @@ ------------------------------------------------------------------------------ --- MIME support for the Lua language. --- Author: Diego Nehab --- Conforming to RFCs 2045-2049 ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local ltn12 = require("ltn12") -local mime = require("mime.core") -local io = require("io") -local string = require("string") -local _M = mime - --- encode, decode and wrap algorithm tables -local encodet, decodet, wrapt = {},{},{} - -_M.encodet = encodet -_M.decodet = decodet -_M.wrapt = wrapt - --- creates a function that chooses a filter by name from a given table -local function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then - base.error("unknown key (" .. base.tostring(name) .. ")", 3) - else return f(opt1, opt2) end - end -end - --- define the encoding filters -encodet['base64'] = function() - return ltn12.filter.cycle(_M.b64, "") -end - -encodet['quoted-printable'] = function(mode) - return ltn12.filter.cycle(_M.qp, "", - (mode == "binary") and "=0D=0A" or "\r\n") -end - --- define the decoding filters -decodet['base64'] = function() - return ltn12.filter.cycle(_M.unb64, "") -end - -decodet['quoted-printable'] = function() - return ltn12.filter.cycle(_M.unqp, "") -end - -local function format(chunk) - if chunk then - if chunk == "" then return "''" - else return string.len(chunk) end - else return "nil" end -end - --- define the line-wrap filters -wrapt['text'] = function(length) - length = length or 76 - return ltn12.filter.cycle(_M.wrp, length, length) -end -wrapt['base64'] = wrapt['text'] -wrapt['default'] = wrapt['text'] - -wrapt['quoted-printable'] = function() - return ltn12.filter.cycle(_M.qpwrp, 76, 76) -end - --- function that choose the encoding, decoding or wrap algorithm -_M.encode = choose(encodet) -_M.decode = choose(decodet) -_M.wrap = choose(wrapt) - --- define the end-of-line normalization filter -function _M.normalize(marker) - return ltn12.filter.cycle(_M.eol, 0, marker) -end - --- high level stuffing filter -function _M.stuff() - return ltn12.filter.cycle(_M.dot, 2) -end - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mobdebug/mobdebug.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mobdebug/mobdebug.lua deleted file mode 100644 index 3f5fdfc..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/mobdebug/mobdebug.lua +++ /dev/null @@ -1,1609 +0,0 @@ --- --- MobDebug -- Lua remote debugger --- Copyright 2011-15 Paul Kulchenko --- Based on RemDebug 1.0 Copyright Kepler Project 2005 --- - --- use loaded modules or load explicitly on those systems that require that -local require = require -local io = io or require "io" -local table = table or require "table" -local string = string or require "string" -local coroutine = coroutine or require "coroutine" -local debug = require "debug" --- protect require "os" as it may fail on embedded systems without os module -local os = os or (function(module) - local ok, res = pcall(require, module) - return ok and res or nil -end)("os") - -local mobdebug = { - _NAME = "mobdebug", - _VERSION = 0.628, - _COPYRIGHT = "Paul Kulchenko", - _DESCRIPTION = "Mobile Remote Debugger for the Lua programming language", - port = os and os.getenv and tonumber((os.getenv("MOBDEBUG_PORT"))) or 8172, - checkcount = 200, - yieldtimeout = 0.02, -- yield timeout (s) - connecttimeout = 2, -- connect timeout (s) -} - -local error = error -local getfenv = getfenv -local setfenv = setfenv -local loadstring = loadstring or load -- "load" replaced "loadstring" in Lua 5.2 -local pairs = pairs -local setmetatable = setmetatable -local tonumber = tonumber -local unpack = table.unpack or unpack -local rawget = rawget -local gsub, sub, find = string.gsub, string.sub, string.find - --- if strict.lua is used, then need to avoid referencing some global --- variables, as they can be undefined; --- use rawget to avoid complaints from strict.lua at run-time. --- it's safe to do the initialization here as all these variables --- should get defined values (if any) before the debugging starts. --- there is also global 'wx' variable, which is checked as part of --- the debug loop as 'wx' can be loaded at any time during debugging. -local genv = _G or _ENV -local jit = rawget(genv, "jit") -local MOAICoroutine = rawget(genv, "MOAICoroutine") - --- ngx_lua debugging requires a special handling as its coroutine.* --- methods use a different mechanism that doesn't allow resume calls --- from debug hook handlers. --- Instead, the "original" coroutine.* methods are used. --- `rawget` needs to be used to protect against `strict` checks, but --- ngx_lua hides those in a metatable, so need to use that. -local metagindex = getmetatable(genv) and getmetatable(genv).__index -local ngx = type(metagindex) == "table" and metagindex.rawget and metagindex:rawget("ngx") or nil -local corocreate = ngx and coroutine._create or coroutine.create -local cororesume = ngx and coroutine._resume or coroutine.resume -local coroyield = ngx and coroutine._yield or coroutine.yield -local corostatus = ngx and coroutine._status or coroutine.status -local corowrap = coroutine.wrap - -if not setfenv then -- Lua 5.2+ - -- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html - -- this assumes f is a function - local function findenv(f) - local level = 1 - repeat - local name, value = debug.getupvalue(f, level) - if name == '_ENV' then return level, value end - level = level + 1 - until name == nil - return nil end - getfenv = function (f) return(select(2, findenv(f)) or _G) end - setfenv = function (f, t) - local level = findenv(f) - if level then debug.setupvalue(f, level, t) end - return f end -end - --- check for OS and convert file names to lower case on windows --- (its file system is case insensitive, but case preserving), as setting a --- breakpoint on x:\Foo.lua will not work if the file was loaded as X:\foo.lua. --- OSX and Windows behave the same way (case insensitive, but case preserving). --- OSX can be configured to be case-sensitive, so check for that. This doesn't --- handle the case of different partitions having different case-sensitivity. -local win = os and os.getenv and (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')) and true or false -local mac = not win and (os and os.getenv and os.getenv('DYLD_LIBRARY_PATH') or not io.open("/proc")) and true or false -local iscasepreserving = win or (mac and io.open('/library') ~= nil) - --- turn jit off based on Mike Pall's comment in this discussion: --- http://www.freelists.org/post/luajit/Debug-hooks-and-JIT,2 --- "You need to turn it off at the start if you plan to receive --- reliable hook calls at any later point in time." -if jit and jit.off then jit.off() end - -local socket = require "socket" -local coro_debugger -local coro_debugee -local coroutines = {}; setmetatable(coroutines, {__mode = "k"}) -- "weak" keys -local events = { BREAK = 1, WATCH = 2, RESTART = 3, STACK = 4 } -local breakpoints = {} -local watches = {} -local lastsource -local lastfile -local watchescnt = 0 -local abort -- default value is nil; this is used in start/loop distinction -local seen_hook = false -local checkcount = 0 -local step_into = false -local step_over = false -local step_level = 0 -local stack_level = 0 -local server -local buf -local outputs = {} -local iobase = {print = print} -local basedir = "" -local deferror = "execution aborted at default debugee" -local debugee = function () - local a = 1 - for _ = 1, 10 do a = a + 1 end - error(deferror) -end -local function q(s) return string.gsub(s, '([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end - -local serpent = (function() ---- include Serpent module for serialization -local n, v = "serpent", 0.285 -- (C) 2012-15 Paul Kulchenko; MIT License -local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" -local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} -local badtype = {thread = true, userdata = true, cdata = true} -local getmetatable = debug and debug.getmetatable or getmetatable -local keyword, globals, G = {}, {}, (_G or _ENV) -for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', - 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', - 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end -for k,v in pairs(G) do globals[v] = k end -- build func to name mapping -for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do - for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end - -local function s(t, opts) - local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum - local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge - local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) - local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) - local numformat = opts.numformat or "%.17g" - local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 - local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)", - -- tostring(val) is needed because __tostring may return a non-string value - function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end - local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or numformat:format(s)) - or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 - or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end - local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end - local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal - and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end - local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] - local n = name == nil and '' or name - local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] - local safe = plain and n or '['..safestr(n)..']' - return (path or '')..(plain and path and '.' or '')..safe, safe end - local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding - local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} - local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end - table.sort(k, function(a,b) - -- sort numeric keys first: k[key] is not nil for numerical keys - return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) - < (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end - local function val2str(t, name, indent, insref, path, plainindex, level) - local ttype, level, mt = type(t), (level or 0), getmetatable(t) - local spath, sname = safename(path, name) - local tag = plainindex and - ((type(name) == "number") and '' or name..space..'='..space) or - (name ~= nil and sname..space..'='..space or '') - if seen[t] then -- already seen this element - sref[#sref+1] = spath..space..'='..space..seen[t] - return tag..'nil'..comment('ref', level) end - -- protect from those cases where __tostring may fail - if type(mt) == 'table' and pcall(function() return mt.__tostring and mt.__tostring(t) end) - and (mt.__serialize or mt.__tostring) then -- knows how to serialize itself - seen[t] = insref or spath - if mt.__serialize then t = mt.__serialize(t) else t = tostring(t) end - ttype = type(t) end -- new value falls through to be serialized - if ttype == "table" then - if level >= maxl then return tag..'{}'..comment('max', level) end - seen[t] = insref or spath - if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty - local maxn, o, out = math.min(#t, maxnum or #t), {}, {} - for key = 1, maxn do o[key] = key end - if not maxnum or #o < maxnum then - local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables - for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end - if maxnum and #o > maxnum then o[maxnum+1] = nil end - if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end - local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output) - for n, key in ipairs(o) do - local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse - if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing - or opts.keyallow and not opts.keyallow[key] - or opts.keyignore and opts.keyignore[key] - or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types - or sparse and value == nil then -- skipping nils; do nothing - elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then - if not seen[key] and not globals[key] then - sref[#sref+1] = 'placeholder' - local sname = safename(iname, gensym(key)) -- iname is table for local variables - sref[#sref] = val2str(key,sname,indent,sname,iname,true) end - sref[#sref+1] = 'placeholder' - local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']' - sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path)) - else - out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1) - end - end - local prefix = string.rep(indent or '', level) - local head = indent and '{\n'..prefix..indent or '{' - local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) - local tail = indent and "\n"..prefix..'}' or '}' - return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level) - elseif badtype[ttype] then - seen[t] = insref or spath - return tag..globerr(t, level) - elseif ttype == 'function' then - seen[t] = insref or spath - local ok, res = pcall(string.dump, t) - local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or - "((loadstring or load)("..safestr(res)..",'@serialized'))")..comment(t, level)) - return tag..(func or globerr(t, level)) - else return tag..safestr(t) end -- handle all other types - end - local sepr = indent and "\n" or ";"..space - local body = val2str(t, name, indent) -- this call also populates sref - local tail = #sref>1 and table.concat(sref, sepr)..sepr or '' - local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or '' - return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end" -end - -local function deserialize(data, opts) - local env = (opts and opts.safe == false) and G - or setmetatable({}, { - __index = function(t,k) return t end, - __call = function(t,...) error("cannot call functions") end - }) - local f, res = (loadstring or load)('return '..data, nil, nil, env) - if not f then f, res = (loadstring or load)(data, nil, nil, env) end - if not f then return f, res end - if setfenv then setfenv(f, env) end - return pcall(f) -end - -local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end -return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, - load = deserialize, - dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, - line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, - block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } -end)() ---- end of Serpent module - -mobdebug.line = serpent.line -mobdebug.dump = serpent.dump -mobdebug.linemap = nil -mobdebug.loadstring = loadstring - -local function removebasedir(path, basedir) - if iscasepreserving then - -- check if the lowercased path matches the basedir - -- if so, return substring of the original path (to not lowercase it) - return path:lower():find('^'..q(basedir:lower())) - and path:sub(#basedir+1) or path - else - return string.gsub(path, '^'..q(basedir), '') - end -end - -local function stack(start) - local function vars(f) - local func = debug.getinfo(f, "f").func - local i = 1 - local locals = {} - -- get locals - while true do - local name, value = debug.getlocal(f, i) - if not name then break end - if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end - i = i + 1 - end - -- get varargs (these use negative indices) - i = 1 - while true do - local name, value = debug.getlocal(f, -i) - if not name then break end - locals[name:gsub("%)$"," "..i..")")] = {value, tostring(value)} - i = i + 1 - end - -- get upvalues - i = 1 - local ups = {} - while func and true do -- check for func as it may be nil for tail calls - local name, value = debug.getupvalue(func, i) - if not name then break end - ups[name] = {value, tostring(value)} - i = i + 1 - end - return locals, ups - end - - local stack = {} - local linemap = mobdebug.linemap - for i = (start or 0), 100 do - local source = debug.getinfo(i, "Snl") - if not source then break end - - local src = source.source - if src:find("@") == 1 then - src = src:sub(2):gsub("\\", "/") - if src:find("%./") == 1 then src = src:sub(3) end - end - - table.insert(stack, { -- remove basedir from source - {source.name, removebasedir(src, basedir), - linemap and linemap(source.linedefined, source.source) or source.linedefined, - linemap and linemap(source.currentline, source.source) or source.currentline, - source.what, source.namewhat, source.short_src}, - vars(i+1)}) - if source.what == 'main' then break end - end - return stack -end - -local function set_breakpoint(file, line) - if file == '-' and lastfile then file = lastfile - elseif iscasepreserving then file = string.lower(file) end - if not breakpoints[line] then breakpoints[line] = {} end - breakpoints[line][file] = true -end - -local function remove_breakpoint(file, line) - if file == '-' and lastfile then file = lastfile - elseif file == '*' and line == 0 then breakpoints = {} - elseif iscasepreserving then file = string.lower(file) end - if breakpoints[line] then breakpoints[line][file] = nil end -end - -local function has_breakpoint(file, line) - return breakpoints[line] - and breakpoints[line][iscasepreserving and string.lower(file) or file] -end - -local function restore_vars(vars) - if type(vars) ~= 'table' then return end - - -- locals need to be processed in the reverse order, starting from - -- the inner block out, to make sure that the localized variables - -- are correctly updated with only the closest variable with - -- the same name being changed - -- first loop find how many local variables there is, while - -- the second loop processes them from i to 1 - local i = 1 - while true do - local name = debug.getlocal(3, i) - if not name then break end - i = i + 1 - end - i = i - 1 - local written_vars = {} - while i > 0 do - local name = debug.getlocal(3, i) - if not written_vars[name] then - if string.sub(name, 1, 1) ~= '(' then - debug.setlocal(3, i, rawget(vars, name)) - end - written_vars[name] = true - end - i = i - 1 - end - - i = 1 - local func = debug.getinfo(3, "f").func - while true do - local name = debug.getupvalue(func, i) - if not name then break end - if not written_vars[name] then - if string.sub(name, 1, 1) ~= '(' then - debug.setupvalue(func, i, rawget(vars, name)) - end - written_vars[name] = true - end - i = i + 1 - end -end - -local function capture_vars(level) - local vars = {} - local func = debug.getinfo(level or 3, "f").func - local i = 1 - while true do - local name, value = debug.getupvalue(func, i) - if not name then break end - if string.sub(name, 1, 1) ~= '(' then vars[name] = value end - i = i + 1 - end - i = 1 - while true do - local name, value = debug.getlocal(level or 3, i) - if not name then break end - if string.sub(name, 1, 1) ~= '(' then vars[name] = value end - i = i + 1 - end - -- returned 'vars' table plays a dual role: (1) it captures local values - -- and upvalues to be restored later (in case they are modified in "eval"), - -- and (2) it provides an environment for evaluated chunks. - -- getfenv(func) is needed to provide proper environment for functions, - -- including access to globals, but this causes vars[name] to fail in - -- restore_vars on local variables or upvalues with `nil` values when - -- 'strict' is in effect. To avoid this `rawget` is used in restore_vars. - setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) }) - return vars -end - -local function stack_depth(start_depth) - for i = start_depth, 0, -1 do - if debug.getinfo(i, "l") then return i+1 end - end - return start_depth -end - -local function is_safe(stack_level) - -- the stack grows up: 0 is getinfo, 1 is is_safe, 2 is debug_hook, 3 is user function - if stack_level == 3 then return true end - for i = 3, stack_level do - -- return if it is not safe to abort - local info = debug.getinfo(i, "S") - if not info then return true end - if info.what == "C" then return false end - end - return true -end - -local function in_debugger() - local this = debug.getinfo(1, "S").source - -- only need to check few frames as mobdebug frames should be close - for i = 3, 7 do - local info = debug.getinfo(i, "S") - if not info then return false end - if info.source == this then return true end - end - return false -end - -local function is_pending(peer) - -- if there is something already in the buffer, skip check - if not buf and checkcount >= mobdebug.checkcount then - peer:settimeout(0) -- non-blocking - buf = peer:receive(1) - peer:settimeout() -- back to blocking - checkcount = 0 - end - return buf -end - -local function readnext(peer, num) - peer:settimeout(0) -- non-blocking - local res, err, partial = peer:receive(num) - peer:settimeout() -- back to blocking - return res or partial or '', err -end - -local function handle_breakpoint(peer) - -- check if the buffer has the beginning of SETB/DELB command; - -- this is to avoid reading the entire line for commands that - -- don't need to be handled here. - if not buf or not (buf:sub(1,1) == 'S' or buf:sub(1,1) == 'D') then return end - - -- check second character to avoid reading STEP or other S* and D* commands - if #buf == 1 then buf = buf .. readnext(peer, 1) end - if buf:sub(2,2) ~= 'E' then return end - - -- need to read few more characters - buf = buf .. readnext(peer, 5-#buf) - if buf ~= 'SETB ' and buf ~= 'DELB ' then return end - - local res, _, partial = peer:receive() -- get the rest of the line; blocking - if not res then - if partial then buf = buf .. partial end - return - end - - local _, _, cmd, file, line = (buf..res):find("^([A-Z]+)%s+(.-)%s+(%d+)%s*$") - if cmd == 'SETB' then set_breakpoint(file, tonumber(line)) - elseif cmd == 'DELB' then remove_breakpoint(file, tonumber(line)) - else - -- this looks like a breakpoint command, but something went wrong; - -- return here to let the "normal" processing to handle, - -- although this is likely to not go well. - return - end - - buf = nil -end - -local function debug_hook(event, line) - -- (1) LuaJIT needs special treatment. Because debug_hook is set for - -- *all* coroutines, and not just the one being debugged as in regular Lua - -- (http://lua-users.org/lists/lua-l/2011-06/msg00513.html), - -- need to avoid debugging mobdebug's own code as LuaJIT doesn't - -- always correctly generate call/return hook events (there are more - -- calls than returns, which breaks stack depth calculation and - -- 'step' and 'step over' commands stop working; possibly because - -- 'tail return' events are not generated by LuaJIT). - -- the next line checks if the debugger is run under LuaJIT and if - -- one of debugger methods is present in the stack, it simply returns. - if jit then - -- when luajit is compiled with LUAJIT_ENABLE_LUA52COMPAT, - -- coroutine.running() returns non-nil for the main thread. - local coro, main = coroutine.running() - if not coro or main then coro = 'main' end - local disabled = coroutines[coro] == false - or coroutines[coro] == nil and coro ~= (coro_debugee or 'main') - if coro_debugee and disabled or not coro_debugee and (disabled or in_debugger()) - then return end - end - - -- (2) check if abort has been requested and it's safe to abort - if abort and is_safe(stack_level) then error(abort) end - - -- (3) also check if this debug hook has not been visited for any reason. - -- this check is needed to avoid stepping in too early - -- (for example, when coroutine.resume() is executed inside start()). - if not seen_hook and in_debugger() then return end - - if event == "call" then - stack_level = stack_level + 1 - elseif event == "return" or event == "tail return" then - stack_level = stack_level - 1 - elseif event == "line" then - if mobdebug.linemap then - local ok, mappedline = pcall(mobdebug.linemap, line, debug.getinfo(2, "S").source) - if ok then line = mappedline end - if not line then return end - end - - -- may need to fall through because of the following: - -- (1) step_into - -- (2) step_over and stack_level <= step_level (need stack_level) - -- (3) breakpoint; check for line first as it's known; then for file - -- (4) socket call (only do every Xth check) - -- (5) at least one watch is registered - if not ( - step_into or step_over or breakpoints[line] or watchescnt > 0 - or is_pending(server) - ) then checkcount = checkcount + 1; return end - - checkcount = mobdebug.checkcount -- force check on the next command - - -- this is needed to check if the stack got shorter or longer. - -- unfortunately counting call/return calls is not reliable. - -- the discrepancy may happen when "pcall(load, '')" call is made - -- or when "error()" is called in a function. - -- in either case there are more "call" than "return" events reported. - -- this validation is done for every "line" event, but should be "cheap" - -- as it checks for the stack to get shorter (or longer by one call). - -- start from one level higher just in case we need to grow the stack. - -- this may happen after coroutine.resume call to a function that doesn't - -- have any other instructions to execute. it triggers three returns: - -- "return, tail return, return", which needs to be accounted for. - stack_level = stack_depth(stack_level+1) - - local caller = debug.getinfo(2, "S") - - -- grab the filename and fix it if needed - local file = lastfile - if (lastsource ~= caller.source) then - file, lastsource = caller.source, caller.source - -- technically, users can supply names that may not use '@', - -- for example when they call loadstring('...', 'filename.lua'). - -- Unfortunately, there is no reliable/quick way to figure out - -- what is the filename and what is the source code. - -- The following will work if the supplied filename uses Unix path. - if find(file, "^@") then - file = gsub(gsub(file, "^@", ""), "\\", "/") - -- need this conversion to be applied to relative and absolute - -- file names as you may write "require 'Foo'" to - -- load "foo.lua" (on a case insensitive file system) and breakpoints - -- set on foo.lua will not work if not converted to the same case. - if iscasepreserving then file = string.lower(file) end - if find(file, "%./") == 1 then file = sub(file, 3) - else file = gsub(file, "^"..q(basedir), "") end - -- some file systems allow newlines in file names; remove these. - file = gsub(file, "\n", ' ') - else - -- this is either a file name coming from loadstring("chunk", "file"), - -- or the actual source code that needs to be serialized (as it may - -- include newlines); assume it's a file name if it's all on one line. - if find(file, "[\r\n]") then - file = mobdebug.line(file) - else - if iscasepreserving then file = string.lower(file) end - file = gsub(gsub(file, "\\", "/"), find(file, "^%./") and "^%./" or "^"..q(basedir), "") - end - end - - -- set to true if we got here; this only needs to be done once per - -- session, so do it here to at least avoid setting it for every line. - seen_hook = true - lastfile = file - end - - if is_pending(server) then handle_breakpoint(server) end - - local vars, status, res - if (watchescnt > 0) then - vars = capture_vars() - for index, value in pairs(watches) do - setfenv(value, vars) - local ok, fired = pcall(value) - if ok and fired then - status, res = cororesume(coro_debugger, events.WATCH, vars, file, line, index) - break -- any one watch is enough; don't check multiple times - end - end - end - - -- need to get into the "regular" debug handler, but only if there was - -- no watch that was fired. If there was a watch, handle its result. - local getin = (status == nil) and - (step_into - -- when coroutine.running() return `nil` (main thread in Lua 5.1), - -- step_over will equal 'main', so need to check for that explicitly. - or (step_over and step_over == (coroutine.running() or 'main') and stack_level <= step_level) - or has_breakpoint(file, line) - or is_pending(server)) - - if getin then - vars = vars or capture_vars() - step_into = false - step_over = false - status, res = cororesume(coro_debugger, events.BREAK, vars, file, line) - end - - -- handle 'stack' command that provides stack() information to the debugger - if status and res == 'stack' then - while status and res == 'stack' do - -- resume with the stack trace and variables - if vars then restore_vars(vars) end -- restore vars so they are reflected in stack values - -- this may fail if __tostring method fails at run-time - local ok, snapshot = pcall(stack, ngx and 5 or 4) - status, res = cororesume(coro_debugger, ok and events.STACK or events.BREAK, snapshot, file, line) - end - end - - -- need to recheck once more as resume after 'stack' command may - -- return something else (for example, 'exit'), which needs to be handled - if status and res and res ~= 'stack' then - if not abort and res == "exit" then mobdebug.onexit(1, true); return end - if not abort and res == "done" then mobdebug.done(); return end - abort = res - -- only abort if safe; if not, there is another (earlier) check inside - -- debug_hook, which will abort execution at the first safe opportunity - if is_safe(stack_level) then error(abort) end - elseif not status and res then - error(res, 2) -- report any other (internal) errors back to the application - end - - if vars then restore_vars(vars) end - - -- last command requested Step Over/Out; store the current thread - if step_over == true then step_over = coroutine.running() or 'main' end - end -end - -local function stringify_results(status, ...) - if not status then return status, ... end -- on error report as it - - local t = {...} - for i,v in pairs(t) do -- stringify each of the returned values - local ok, res = pcall(mobdebug.line, v, {nocode = true, comment = 1}) - t[i] = ok and res or ("%q"):format(res):gsub("\010","n"):gsub("\026","\\026") - end - -- stringify table with all returned values - -- this is done to allow each returned value to be used (serialized or not) - -- intependently and to preserve "original" comments - return pcall(mobdebug.dump, t, {sparse = false}) -end - -local function isrunning() - return coro_debugger and (corostatus(coro_debugger) == 'suspended' or corostatus(coro_debugger) == 'running') -end - --- this is a function that removes all hooks and closes the socket to --- report back to the controller that the debugging is done. --- the script that called `done` can still continue. -local function done() - if not (isrunning() and server) then return end - - if not jit then - for co, debugged in pairs(coroutines) do - if debugged then debug.sethook(co) end - end - end - - debug.sethook() - server:close() - - coro_debugger = nil -- to make sure isrunning() returns `false` - seen_hook = nil -- to make sure that the next start() call works - abort = nil -- to make sure that callback calls use proper "abort" value -end - -local function debugger_loop(sev, svars, sfile, sline) - local command - local app, osname - local eval_env = svars or {} - local function emptyWatch () return false end - local loaded = {} - for k in pairs(package.loaded) do loaded[k] = true end - - while true do - local line, err - local wx = rawget(genv, "wx") -- use rawread to make strict.lua happy - if (wx or mobdebug.yield) and server.settimeout then server:settimeout(mobdebug.yieldtimeout) end - while true do - line, err = server:receive() - if not line and err == "timeout" then - -- yield for wx GUI applications if possible to avoid "busyness" - app = app or (wx and wx.wxGetApp and wx.wxGetApp()) - if app then - local win = app:GetTopWindow() - local inloop = app:IsMainLoopRunning() - osname = osname or wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName() - if win and not inloop then - -- process messages in a regular way - -- and exit as soon as the event loop is idle - if osname == 'Unix' then wx.wxTimer(app):Start(10, true) end - local exitLoop = function() - win:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_IDLE) - win:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_TIMER) - app:ExitMainLoop() - end - win:Connect(wx.wxEVT_IDLE, exitLoop) - win:Connect(wx.wxEVT_TIMER, exitLoop) - app:MainLoop() - end - elseif mobdebug.yield then mobdebug.yield() - end - elseif not line and err == "closed" then - error("Debugger connection closed", 0) - else - -- if there is something in the pending buffer, prepend it to the line - if buf then line = buf .. line; buf = nil end - break - end - end - if server.settimeout then server:settimeout() end -- back to blocking - command = string.sub(line, string.find(line, "^[A-Z]+")) - if command == "SETB" then - local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$") - if file and line then - set_breakpoint(file, tonumber(line)) - server:send("200 OK\n") - else - server:send("400 Bad Request\n") - end - elseif command == "DELB" then - local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$") - if file and line then - remove_breakpoint(file, tonumber(line)) - server:send("200 OK\n") - else - server:send("400 Bad Request\n") - end - elseif command == "EXEC" then - local _, _, chunk = string.find(line, "^[A-Z]+%s+(.+)$") - if chunk then - local func, res = mobdebug.loadstring(chunk) - local status - if func then - setfenv(func, eval_env) - status, res = stringify_results(pcall(func)) - end - if status then - server:send("200 OK " .. tostring(#res) .. "\n") - server:send(res) - else - -- fix error if not set (for example, when loadstring is not present) - if not res then res = "Unknown error" end - server:send("401 Error in Expression " .. tostring(#res) .. "\n") - server:send(res) - end - else - server:send("400 Bad Request\n") - end - elseif command == "LOAD" then - local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+(%S.-)%s*$") - size = tonumber(size) - - if abort == nil then -- no LOAD/RELOAD allowed inside start() - if size > 0 then server:receive(size) end - if sfile and sline then - server:send("201 Started " .. sfile .. " " .. tostring(sline) .. "\n") - else - server:send("200 OK 0\n") - end - else - -- reset environment to allow required modules to load again - -- remove those packages that weren't loaded when debugger started - for k in pairs(package.loaded) do - if not loaded[k] then package.loaded[k] = nil end - end - - if size == 0 and name == '-' then -- RELOAD the current script being debugged - server:send("200 OK 0\n") - coroyield("load") - else - -- receiving 0 bytes blocks (at least in luasocket 2.0.2), so skip reading - local chunk = size == 0 and "" or server:receive(size) - if chunk then -- LOAD a new script for debugging - local func, res = mobdebug.loadstring(chunk, "@"..name) - if func then - server:send("200 OK 0\n") - debugee = func - coroyield("load") - else - server:send("401 Error in Expression " .. tostring(#res) .. "\n") - server:send(res) - end - else - server:send("400 Bad Request\n") - end - end - end - elseif command == "SETW" then - local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$") - if exp then - local func, res = mobdebug.loadstring("return(" .. exp .. ")") - if func then - watchescnt = watchescnt + 1 - local newidx = #watches + 1 - watches[newidx] = func - server:send("200 OK " .. tostring(newidx) .. "\n") - else - server:send("401 Error in Expression " .. tostring(#res) .. "\n") - server:send(res) - end - else - server:send("400 Bad Request\n") - end - elseif command == "DELW" then - local _, _, index = string.find(line, "^[A-Z]+%s+(%d+)%s*$") - index = tonumber(index) - if index > 0 and index <= #watches then - watchescnt = watchescnt - (watches[index] ~= emptyWatch and 1 or 0) - watches[index] = emptyWatch - server:send("200 OK\n") - else - server:send("400 Bad Request\n") - end - elseif command == "RUN" then - server:send("200 OK\n") - - local ev, vars, file, line, idx_watch = coroyield() - eval_env = vars - if ev == events.BREAK then - server:send("202 Paused " .. file .. " " .. tostring(line) .. "\n") - elseif ev == events.WATCH then - server:send("203 Paused " .. file .. " " .. tostring(line) .. " " .. tostring(idx_watch) .. "\n") - elseif ev == events.RESTART then - -- nothing to do - else - server:send("401 Error in Execution " .. tostring(#file) .. "\n") - server:send(file) - end - elseif command == "STEP" then - server:send("200 OK\n") - step_into = true - - local ev, vars, file, line, idx_watch = coroyield() - eval_env = vars - if ev == events.BREAK then - server:send("202 Paused " .. file .. " " .. tostring(line) .. "\n") - elseif ev == events.WATCH then - server:send("203 Paused " .. file .. " " .. tostring(line) .. " " .. tostring(idx_watch) .. "\n") - elseif ev == events.RESTART then - -- nothing to do - else - server:send("401 Error in Execution " .. tostring(#file) .. "\n") - server:send(file) - end - elseif command == "OVER" or command == "OUT" then - server:send("200 OK\n") - step_over = true - - -- OVER and OUT are very similar except for - -- the stack level value at which to stop - if command == "OUT" then step_level = stack_level - 1 - else step_level = stack_level end - - local ev, vars, file, line, idx_watch = coroyield() - eval_env = vars - if ev == events.BREAK then - server:send("202 Paused " .. file .. " " .. tostring(line) .. "\n") - elseif ev == events.WATCH then - server:send("203 Paused " .. file .. " " .. tostring(line) .. " " .. tostring(idx_watch) .. "\n") - elseif ev == events.RESTART then - -- nothing to do - else - server:send("401 Error in Execution " .. tostring(#file) .. "\n") - server:send(file) - end - elseif command == "BASEDIR" then - local _, _, dir = string.find(line, "^[A-Z]+%s+(.+)%s*$") - if dir then - basedir = iscasepreserving and string.lower(dir) or dir - -- reset cached source as it may change with basedir - lastsource = nil - server:send("200 OK\n") - else - server:send("400 Bad Request\n") - end - elseif command == "SUSPEND" then - -- do nothing; it already fulfilled its role - elseif command == "DONE" then - coroyield("done") - return -- done with all the debugging - elseif command == "STACK" then - -- first check if we can execute the stack command - -- as it requires yielding back to debug_hook it cannot be executed - -- if we have not seen the hook yet as happens after start(). - -- in this case we simply return an empty result - local vars, ev = {} - if seen_hook then - ev, vars = coroyield("stack") - end - if ev and ev ~= events.STACK then - server:send("401 Error in Execution " .. tostring(#vars) .. "\n") - server:send(vars) - else - local ok, res = pcall(mobdebug.dump, vars, {nocode = true, sparse = false}) - if ok then - server:send("200 OK " .. tostring(res) .. "\n") - else - server:send("401 Error in Execution " .. tostring(#res) .. "\n") - server:send(res) - end - end - elseif command == "OUTPUT" then - local _, _, stream, mode = string.find(line, "^[A-Z]+%s+(%w+)%s+([dcr])%s*$") - if stream and mode and stream == "stdout" then - -- assign "print" in the global environment - local default = mode == 'd' - genv.print = default and iobase.print or corowrap(function() - -- wrapping into coroutine.wrap protects this function from - -- being stepped through in the debugger. - -- don't use vararg (...) as it adds a reference for its values, - -- which may affect how they are garbage collected - while true do - local tbl = {coroutine.yield()} - if mode == 'c' then iobase.print(unpack(tbl)) end - for n = 1, #tbl do - tbl[n] = select(2, pcall(mobdebug.line, tbl[n], {nocode = true, comment = false})) end - local file = table.concat(tbl, "\t").."\n" - server:send("204 Output " .. stream .. " " .. tostring(#file) .. "\n" .. file) - end - end) - if not default then genv.print() end -- "fake" print to start printing loop - server:send("200 OK\n") - else - server:send("400 Bad Request\n") - end - elseif command == "EXIT" then - server:send("200 OK\n") - coroyield("exit") - else - server:send("400 Bad Request\n") - end - end -end - -local function connect(controller_host, controller_port) - local sock, err = socket.tcp() - if not sock then return nil, err end - - if sock.settimeout then sock:settimeout(mobdebug.connecttimeout) end - local res, err = sock:connect(controller_host, tostring(controller_port)) - if sock.settimeout then sock:settimeout() end - - if not res then return nil, err end - return sock -end - -local lasthost, lastport - --- Starts a debug session by connecting to a controller -local function start(controller_host, controller_port) - -- only one debugging session can be run (as there is only one debug hook) - if isrunning() then return end - - lasthost = controller_host or lasthost - lastport = controller_port or lastport - - controller_host = lasthost or "localhost" - controller_port = lastport or mobdebug.port - - local err - server, err = mobdebug.connect(controller_host, controller_port) - if server then - -- correct stack depth which already has some calls on it - -- so it doesn't go into negative when those calls return - -- as this breaks subsequence checks in stack_depth(). - -- start from 16th frame, which is sufficiently large for this check. - stack_level = stack_depth(16) - - -- provide our own traceback function to report the error remotely - do - local dtraceback = debug.traceback - debug.traceback = function (...) - if select('#', ...) >= 1 then - local err, lvl = ... - if err and type(err) ~= 'thread' then - local trace = dtraceback(err, (lvl or 2)+1) - if genv.print == iobase.print then -- no remote redirect - return trace - else - genv.print(trace) -- report the error remotely - return -- don't report locally to avoid double reporting - end - end - end - -- direct call to debug.traceback: return the original. - -- debug.traceback(nil, level) doesn't work in Lua 5.1 - -- (http://lua-users.org/lists/lua-l/2011-06/msg00574.html), so - -- simply remove first frame from the stack trace - return (dtraceback(...):gsub("(stack traceback:\n)[^\n]*\n", "%1")) - end - end - coro_debugger = corocreate(debugger_loop) - debug.sethook(debug_hook, "lcr") - seen_hook = nil -- reset in case the last start() call was refused - step_into = true -- start with step command - return true - else - print(("Could not connect to %s:%s: %s") - :format(controller_host, controller_port, err or "unknown error")) - end -end - -local function controller(controller_host, controller_port, scratchpad) - -- only one debugging session can be run (as there is only one debug hook) - if isrunning() then return end - - lasthost = controller_host or lasthost - lastport = controller_port or lastport - - controller_host = lasthost or "localhost" - controller_port = lastport or mobdebug.port - - local exitonerror = not scratchpad - local err - server, err = mobdebug.connect(controller_host, controller_port) - if server then - local function report(trace, err) - local msg = err .. "\n" .. trace - server:send("401 Error in Execution " .. tostring(#msg) .. "\n") - server:send(msg) - return err - end - - seen_hook = true -- allow to accept all commands - coro_debugger = corocreate(debugger_loop) - - while true do - step_into = true -- start with step command - abort = false -- reset abort flag from the previous loop - if scratchpad then checkcount = mobdebug.checkcount end -- force suspend right away - - coro_debugee = corocreate(debugee) - debug.sethook(coro_debugee, debug_hook, "lcr") - local status, err = cororesume(coro_debugee) - - -- was there an error or is the script done? - -- 'abort' state is allowed here; ignore it - if abort then - if tostring(abort) == 'exit' then break end - else - if status then -- normal execution is done - break - elseif err and not string.find(tostring(err), deferror) then - -- report the error back - -- err is not necessarily a string, so convert to string to report - report(debug.traceback(coro_debugee), tostring(err)) - if exitonerror then break end - -- check if the debugging is done (coro_debugger is nil) - if not coro_debugger then break end - -- resume once more to clear the response the debugger wants to send - -- need to use capture_vars(2) as three would be the level of - -- the caller for controller(), but because of the tail call, - -- the caller may not exist; - -- This is not entirely safe as the user may see the local - -- variable from console, but they will be reset anyway. - -- This functionality is used when scratchpad is paused to - -- gain access to remote console to modify global variables. - local status, err = cororesume(coro_debugger, events.RESTART, capture_vars(2)) - if not status or status and err == "exit" then break end - end - end - end - else - print(("Could not connect to %s:%s: %s") - :format(controller_host, controller_port, err or "unknown error")) - return false - end - return true -end - -local function scratchpad(controller_host, controller_port) - return controller(controller_host, controller_port, true) -end - -local function loop(controller_host, controller_port) - return controller(controller_host, controller_port, false) -end - -local function on() - if not (isrunning() and server) then return end - - -- main is set to true under Lua5.2 for the "main" chunk. - -- Lua5.1 returns co as `nil` in that case. - local co, main = coroutine.running() - if main then co = nil end - if co then - coroutines[co] = true - debug.sethook(co, debug_hook, "lcr") - else - if jit then coroutines.main = true end - debug.sethook(debug_hook, "lcr") - end -end - -local function off() - if not (isrunning() and server) then return end - - -- main is set to true under Lua5.2 for the "main" chunk. - -- Lua5.1 returns co as `nil` in that case. - local co, main = coroutine.running() - if main then co = nil end - - -- don't remove coroutine hook under LuaJIT as there is only one (global) hook - if co then - coroutines[co] = false - if not jit then debug.sethook(co) end - else - if jit then coroutines.main = false end - if not jit then debug.sethook() end - end - - -- check if there is any thread that is still being debugged under LuaJIT; - -- if not, turn the debugging off - if jit then - local remove = true - for _, debugged in pairs(coroutines) do - if debugged then remove = false; break end - end - if remove then debug.sethook() end - end -end - --- Handles server debugging commands -local function handle(params, client, options) - local _, _, command = string.find(params, "^([a-z]+)") - local file, line, watch_idx - if command == "run" or command == "step" or command == "out" - or command == "over" or command == "exit" then - client:send(string.upper(command) .. "\n") - client:receive() -- this should consume the first '200 OK' response - while true do - local done = true - local breakpoint = client:receive() - if not breakpoint then - print("Program finished") - return - end - local _, _, status = string.find(breakpoint, "^(%d+)") - if status == "200" then - -- don't need to do anything - elseif status == "202" then - _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$") - if file and line then - print("Paused at file " .. file .. " line " .. line) - end - elseif status == "203" then - _, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+(.-)%s+(%d+)%s+(%d+)%s*$") - if file and line and watch_idx then - print("Paused at file " .. file .. " line " .. line .. " (watch expression " .. watch_idx .. ": [" .. watches[watch_idx] .. "])") - end - elseif status == "204" then - local _, _, stream, size = string.find(breakpoint, "^204 Output (%w+) (%d+)$") - if stream and size then - local msg = client:receive(tonumber(size)) - print(msg) - if outputs[stream] then outputs[stream](msg) end - -- this was just the output, so go back reading the response - done = false - end - elseif status == "401" then - local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)$") - if size then - local msg = client:receive(tonumber(size)) - print("Error in remote application: " .. msg) - return nil, nil, msg - end - else - print("Unknown error") - return nil, nil, "Debugger error: unexpected response '" .. breakpoint .. "'" - end - if done then break end - end - elseif command == "done" then - client:send(string.upper(command) .. "\n") - -- no response is expected - elseif command == "setb" or command == "asetb" then - _, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$") - if file and line then - -- if this is a file name, and not a file source - if not file:find('^".*"$') then - file = string.gsub(file, "\\", "/") -- convert slash - file = removebasedir(file, basedir) - end - client:send("SETB " .. file .. " " .. line .. "\n") - if command == "asetb" or client:receive() == "200 OK" then - set_breakpoint(file, line) - else - print("Error: breakpoint not inserted") - end - else - print("Invalid command") - end - elseif command == "setw" then - local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$") - if exp then - client:send("SETW " .. exp .. "\n") - local answer = client:receive() - local _, _, watch_idx = string.find(answer, "^200 OK (%d+)%s*$") - if watch_idx then - watches[watch_idx] = exp - print("Inserted watch exp no. " .. watch_idx) - else - local _, _, size = string.find(answer, "^401 Error in Expression (%d+)$") - if size then - local err = client:receive(tonumber(size)):gsub(".-:%d+:%s*","") - print("Error: watch expression not set: " .. err) - else - print("Error: watch expression not set") - end - end - else - print("Invalid command") - end - elseif command == "delb" or command == "adelb" then - _, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$") - if file and line then - -- if this is a file name, and not a file source - if not file:find('^".*"$') then - file = string.gsub(file, "\\", "/") -- convert slash - file = removebasedir(file, basedir) - end - client:send("DELB " .. file .. " " .. line .. "\n") - if command == "adelb" or client:receive() == "200 OK" then - remove_breakpoint(file, line) - else - print("Error: breakpoint not removed") - end - else - print("Invalid command") - end - elseif command == "delallb" then - local file, line = "*", 0 - client:send("DELB " .. file .. " " .. tostring(line) .. "\n") - if client:receive() == "200 OK" then - remove_breakpoint(file, line) - else - print("Error: all breakpoints not removed") - end - elseif command == "delw" then - local _, _, index = string.find(params, "^[a-z]+%s+(%d+)%s*$") - if index then - client:send("DELW " .. index .. "\n") - if client:receive() == "200 OK" then - watches[index] = nil - else - print("Error: watch expression not removed") - end - else - print("Invalid command") - end - elseif command == "delallw" then - for index, exp in pairs(watches) do - client:send("DELW " .. index .. "\n") - if client:receive() == "200 OK" then - watches[index] = nil - else - print("Error: watch expression at index " .. index .. " [" .. exp .. "] not removed") - end - end - elseif command == "eval" or command == "exec" - or command == "load" or command == "loadstring" - or command == "reload" then - local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$") - if exp or (command == "reload") then - if command == "eval" or command == "exec" then - exp = (exp:gsub("%-%-%[(=*)%[.-%]%1%]", "") -- remove comments - :gsub("%-%-.-\n", " ") -- remove line comments - :gsub("\n", " ")) -- convert new lines - if command == "eval" then exp = "return " .. exp end - client:send("EXEC " .. exp .. "\n") - elseif command == "reload" then - client:send("LOAD 0 -\n") - elseif command == "loadstring" then - local _, _, _, file, lines = string.find(exp, "^([\"'])(.-)%1%s+(.+)") - if not file then - _, _, file, lines = string.find(exp, "^(%S+)%s+(.+)") - end - client:send("LOAD " .. tostring(#lines) .. " " .. file .. "\n") - client:send(lines) - else - local file = io.open(exp, "r") - if not file and pcall(require, "winapi") then - -- if file is not open and winapi is there, try with a short path; - -- this may be needed for unicode paths on windows - winapi.set_encoding(winapi.CP_UTF8) - local shortp = winapi.short_path(exp) - file = shortp and io.open(shortp, "r") - end - if not file then return nil, nil, "Cannot open file " .. exp end - -- read the file and remove the shebang line as it causes a compilation error - local lines = file:read("*all"):gsub("^#!.-\n", "\n") - file:close() - - local file = string.gsub(exp, "\\", "/") -- convert slash - file = removebasedir(file, basedir) - client:send("LOAD " .. tostring(#lines) .. " " .. file .. "\n") - if #lines > 0 then client:send(lines) end - end - while true do - local params, err = client:receive() - if not params then - return nil, nil, "Debugger connection " .. (err or "error") - end - local done = true - local _, _, status, len = string.find(params, "^(%d+).-%s+(%d+)%s*$") - if status == "200" then - len = tonumber(len) - if len > 0 then - local status, res - local str = client:receive(len) - -- handle serialized table with results - local func, err = loadstring(str) - if func then - status, res = pcall(func) - if not status then err = res - elseif type(res) ~= "table" then - err = "received "..type(res).." instead of expected 'table'" - end - end - if err then - print("Error in processing results: " .. err) - return nil, nil, "Error in processing results: " .. err - end - print(unpack(res)) - return res[1], res - end - elseif status == "201" then - _, _, file, line = string.find(params, "^201 Started%s+(.-)%s+(%d+)%s*$") - elseif status == "202" or params == "200 OK" then - -- do nothing; this only happens when RE/LOAD command gets the response - -- that was for the original command that was aborted - elseif status == "204" then - local _, _, stream, size = string.find(params, "^204 Output (%w+) (%d+)$") - if stream and size then - local msg = client:receive(tonumber(size)) - print(msg) - if outputs[stream] then outputs[stream](msg) end - -- this was just the output, so go back reading the response - done = false - end - elseif status == "401" then - len = tonumber(len) - local res = client:receive(len) - print("Error in expression: " .. res) - return nil, nil, res - else - print("Unknown error") - return nil, nil, "Debugger error: unexpected response after EXEC/LOAD '" .. params .. "'" - end - if done then break end - end - else - print("Invalid command") - end - elseif command == "listb" then - for l, v in pairs(breakpoints) do - for f in pairs(v) do - print(f .. ": " .. l) - end - end - elseif command == "listw" then - for i, v in pairs(watches) do - print("Watch exp. " .. i .. ": " .. v) - end - elseif command == "suspend" then - client:send("SUSPEND\n") - elseif command == "stack" then - client:send("STACK\n") - local resp = client:receive() - local _, _, status, res = string.find(resp, "^(%d+)%s+%w+%s+(.+)%s*$") - if status == "200" then - local func, err = loadstring(res) - if func == nil then - print("Error in stack information: " .. err) - return nil, nil, err - end - local ok, stack = pcall(func) - if not ok then - print("Error in stack information: " .. stack) - return nil, nil, stack - end - for _,frame in ipairs(stack) do - print(mobdebug.line(frame[1], {comment = false})) - end - return stack - elseif status == "401" then - local _, _, len = string.find(resp, "%s+(%d+)%s*$") - len = tonumber(len) - local res = len > 0 and client:receive(len) or "Invalid stack information." - print("Error in expression: " .. res) - return nil, nil, res - else - print("Unknown error") - return nil, nil, "Debugger error: unexpected response after STACK" - end - elseif command == "output" then - local _, _, stream, mode = string.find(params, "^[a-z]+%s+(%w+)%s+([dcr])%s*$") - if stream and mode then - client:send("OUTPUT "..stream.." "..mode.."\n") - local resp = client:receive() - local _, _, status = string.find(resp, "^(%d+)%s+%w+%s*$") - if status == "200" then - print("Stream "..stream.." redirected") - outputs[stream] = type(options) == 'table' and options.handler or nil - else - print("Unknown error") - return nil, nil, "Debugger error: can't redirect "..stream - end - else - print("Invalid command") - end - elseif command == "basedir" then - local _, _, dir = string.find(params, "^[a-z]+%s+(.+)$") - if dir then - dir = string.gsub(dir, "\\", "/") -- convert slash - if not string.find(dir, "/$") then dir = dir .. "/" end - - local remdir = dir:match("\t(.+)") - if remdir then dir = dir:gsub("/?\t.+", "/") end - basedir = dir - - client:send("BASEDIR "..(remdir or dir).."\n") - local resp, err = client:receive() - if not resp then - print("Unknown error: "..err) - return nil, nil, "Debugger connection closed" - end - local _, _, status = string.find(resp, "^(%d+)%s+%w+%s*$") - if status == "200" then - print("New base directory is " .. basedir) - else - print("Unknown error") - return nil, nil, "Debugger error: unexpected response after BASEDIR" - end - else - print(basedir) - end - elseif command == "help" then - print("setb -- sets a breakpoint") - print("delb -- removes a breakpoint") - print("delallb -- removes all breakpoints") - print("setw -- adds a new watch expression") - print("delw -- removes the watch expression at index") - print("delallw -- removes all watch expressions") - print("run -- runs until next breakpoint") - print("step -- runs until next line, stepping into function calls") - print("over -- runs until next line, stepping over function calls") - print("out -- runs until line after returning from current function") - print("listb -- lists breakpoints") - print("listw -- lists watch expressions") - print("eval -- evaluates expression on the current context and returns its value") - print("exec -- executes statement on the current context") - print("load -- loads a local file for debugging") - print("reload -- restarts the current debugging session") - print("stack -- reports stack trace") - print("output stdout -- capture and redirect io stream (default|copy|redirect)") - print("basedir [] -- sets the base path of the remote application, or shows the current one") - print("done -- stops the debugger and continues application execution") - print("exit -- exits debugger and the application") - else - local _, _, spaces = string.find(params, "^(%s*)$") - if spaces then - return nil, nil, "Empty command" - else - print("Invalid command") - return nil, nil, "Invalid command" - end - end - return file, line -end - --- Starts debugging server -local function listen(host, port) - host = host or "*" - port = port or mobdebug.port - - local socket = require "socket" - - print("Lua Remote Debugger") - print("Run the program you wish to debug") - - local server = socket.bind(host, port) - local client = server:accept() - - client:send("STEP\n") - client:receive() - - local breakpoint = client:receive() - local _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$") - if file and line then - print("Paused at file " .. file ) - print("Type 'help' for commands") - else - local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)%s*$") - if size then - print("Error in remote application: ") - print(client:receive(size)) - end - end - - while true do - io.write("> ") - local file, line, err = handle(io.read("*line"), client) - if not file and not err then break end -- completed debugging - end - - client:close() -end - -local cocreate -local function coro() - if cocreate then return end -- only set once - cocreate = cocreate or coroutine.create - coroutine.create = function(f, ...) - return cocreate(function(...) - mobdebug.on() - return f(...) - end, ...) - end -end - -local moconew -local function moai() - if moconew then return end -- only set once - moconew = moconew or (MOAICoroutine and MOAICoroutine.new) - if not moconew then return end - MOAICoroutine.new = function(...) - local thread = moconew(...) - -- need to support both thread.run and getmetatable(thread).run, which - -- was used in earlier MOAI versions - local mt = thread.run and thread or getmetatable(thread) - local patched = mt.run - mt.run = function(self, f, ...) - return patched(self, function(...) - mobdebug.on() - return f(...) - end, ...) - end - return thread - end -end - --- make public functions available -mobdebug.setbreakpoint = set_breakpoint -mobdebug.removebreakpoint = remove_breakpoint -mobdebug.listen = listen -mobdebug.loop = loop -mobdebug.scratchpad = scratchpad -mobdebug.handle = handle -mobdebug.connect = connect -mobdebug.start = start -mobdebug.on = on -mobdebug.off = off -mobdebug.moai = moai -mobdebug.coro = coro -mobdebug.done = done -mobdebug.pause = function() step_into = true end -mobdebug.yield = nil -- callback -mobdebug.onexit = os and os.exit or done -mobdebug.basedir = function(b) if b then basedir = b end return basedir end - -return mobdebug diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/sha2.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/sha2.lua deleted file mode 100644 index 66795d6..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/sha2.lua +++ /dev/null @@ -1,239 +0,0 @@ --- SHA-256 code in Lua 5.2; based on the pseudo-code from --- Wikipedia (http://en.wikipedia.org/wiki/SHA-2) --- from http://lua-users.org/wiki/SecureHashAlgorithm - -local band, rrotate, bxor, rshift, bnot = - bit32.band, bit32.rrotate, bit32.bxor, bit32.rshift, bit32.bnot - -local string, setmetatable, assert = string, setmetatable, assert - --- Initialize table of round constants --- (first 32 bits of the fractional parts of the cube roots of the first --- 64 primes 2..311): -local k = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -} - - --- transform a string of bytes in a string of hexadecimal digits -local function str2hexa (s) - local h = string.gsub(s, ".", function(c) - return string.format("%02x", string.byte(c)) - end) - return h -end - - --- transform number 'l' in a big-endian sequence of 'n' bytes --- (coded as a string) -local function num2s (l, n) - local s = "" - for i = 1, n do - local rem = l % 256 - s = string.char(rem) .. s - l = (l - rem) / 256 - end - return s -end - --- transform the big-endian sequence of four bytes starting at --- index 'i' in 's' into a number -local function s232num (s, i) - local n = 0 - for i = i, i + 3 do - n = n*256 + string.byte(s, i) - end - return n -end - - --- append the bit '1' to the message --- append k bits '0', where k is the minimum number >= 0 such that the --- resulting message length (in bits) is congruent to 448 (mod 512) --- append length of message (before pre-processing), in bits, as 64-bit --- big-endian integer -local function preproc (msg, len) - local extra = 64 - ((len + 1 + 8) % 64) - len = num2s(8 * len, 8) -- original len in bits, coded - msg = msg .. "\128" .. string.rep("\0", extra) .. len - assert(#msg % 64 == 0) - return msg -end - - -local function initH224 (H) - -- (second 32 bits of the fractional parts of the square roots of the - -- 9th through 16th primes 23..53) - H[1] = 0xc1059ed8 - H[2] = 0x367cd507 - H[3] = 0x3070dd17 - H[4] = 0xf70e5939 - H[5] = 0xffc00b31 - H[6] = 0x68581511 - H[7] = 0x64f98fa7 - H[8] = 0xbefa4fa4 - return H -end - - -local function initH256 (H) - -- (first 32 bits of the fractional parts of the square roots of the - -- first 8 primes 2..19): - H[1] = 0x6a09e667 - H[2] = 0xbb67ae85 - H[3] = 0x3c6ef372 - H[4] = 0xa54ff53a - H[5] = 0x510e527f - H[6] = 0x9b05688c - H[7] = 0x1f83d9ab - H[8] = 0x5be0cd19 - return H -end - - -local function digestblock (msg, i, H) - - -- break chunk into sixteen 32-bit big-endian words w[1..16] - local w = {} - for j = 1, 16 do - w[j] = s232num(msg, i + (j - 1)*4) - end - - -- Extend the sixteen 32-bit words into sixty-four 32-bit words: - for j = 17, 64 do - local v = w[j - 15] - local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3)) - v = w[j - 2] - local s1 = bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10)) - w[j] = w[j - 16] + s0 + w[j - 7] + s1 - end - - -- Initialize hash value for this chunk: - local a, b, c, d, e, f, g, h = - H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] - - -- Main loop: - for i = 1, 64 do - local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22)) - local maj = bxor(band(a, b), band(a, c), band(b, c)) - local t2 = s0 + maj - local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25)) - local ch = bxor (band(e, f), band(bnot(e), g)) - local t1 = h + s1 + ch + k[i] + w[i] - - h = g - g = f - f = e - e = d + t1 - d = c - c = b - b = a - a = t1 + t2 - end - - -- Add (mod 2^32) this chunk's hash to result so far: - H[1] = band(H[1] + a) - H[2] = band(H[2] + b) - H[3] = band(H[3] + c) - H[4] = band(H[4] + d) - H[5] = band(H[5] + e) - H[6] = band(H[6] + f) - H[7] = band(H[7] + g) - H[8] = band(H[8] + h) - -end - - -local function finalresult224 (H) - -- Produce the final hash value (big-endian): - return - str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4).. - num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4)) -end - - -local function finalresult256 (H) - -- Produce the final hash value (big-endian): - return - str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4).. - num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4)..num2s(H[8], 4)) -end - - ----------------------------------------------------------------------- -local HH = {} -- to reuse - -local function hash224 (msg) - msg = preproc(msg, #msg) - local H = initH224(HH) - - -- Process the message in successive 512-bit (64 bytes) chunks: - for i = 1, #msg, 64 do - digestblock(msg, i, H) - end - - return finalresult224(H) -end - - -local function hash256 (msg) - msg = preproc(msg, #msg) - local H = initH256(HH) - - -- Process the message in successive 512-bit (64 bytes) chunks: - for i = 1, #msg, 64 do - digestblock(msg, i, H) - end - - return finalresult256(H) -end ----------------------------------------------------------------------- -local mt = {} - -local function new256 () - local o = {H = initH256({}), msg = "", len = 0} - setmetatable(o, mt) - return o -end - -mt.__index = mt - -function mt:add (m) - self.msg = self.msg .. m - self.len = self.len + #m - local t = 0 - while #self.msg - t >= 64 do - digestblock(self.msg, t + 1, self.H) - t = t + 64 - end - self.msg = self.msg:sub(t + 1, -1) -end - - -function mt:close () - self.msg = preproc(self.msg, self.len) - self:add("") - return finalresult256(self.H) -end ----------------------------------------------------------------------- - -return { - hash224 = hash224, - hash256 = hash256, - new256 = new256, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket.lua deleted file mode 100644 index c3b5f50..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket.lua +++ /dev/null @@ -1,165 +0,0 @@ ------------------------------------------------------------------------------ --- LuaSocket helper module --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local math = require("math") -local socket = require("socket.core") - -local _M = socket - --- this is needed in case this library is used when "socket.core" is loaded, --- but has an older version of luasocket that does not include `connect`. -if not socket.connect then - socket.connect = function (address, port, laddress, lport) - local sock, err = socket.tcp() - if not sock then return nil, err end - if laddress then - local res, err = sock:bind(laddress, lport, -1) - if not res then return nil, err end - end - local res, err = sock:connect(address, port) - if not res then return nil, err end - return sock - end -end - ------------------------------------------------------------------------------ --- Exported auxiliar functions ------------------------------------------------------------------------------ -function _M.connect4(address, port, laddress, lport) - return socket.connect(address, port, laddress, lport, "inet") -end - -function _M.connect6(address, port, laddress, lport) - return socket.connect(address, port, laddress, lport, "inet6") -end - -function _M.bind(host, port, backlog) - if host == "*" then host = "0.0.0.0" end - local addrinfo, err = socket.dns.getaddrinfo(host); - if not addrinfo then return nil, err end - local sock, res - err = "no info on address" - for i, alt in base.ipairs(addrinfo) do - if alt.family == "inet" then - sock, err = socket.tcp() - else - sock, err = socket.tcp6() - end - if not sock then return nil, err end - sock:setoption("reuseaddr", true) - res, err = sock:bind(alt.addr, port) - if not res then - sock:close() - else - res, err = sock:listen(backlog) - if not res then - sock:close() - else - return sock - end - end - end - return nil, err -end - -_M.try = _M.newtry() - -function _M.choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) - else return f(opt1, opt2) end - end -end - ------------------------------------------------------------------------------ --- Socket sources and sinks, conforming to LTN12 ------------------------------------------------------------------------------ --- create namespaces inside LuaSocket namespace -local sourcet, sinkt = {}, {} -_M.sourcet = sourcet -_M.sinkt = sinkt - -_M.BLOCKSIZE = 2048 - -sinkt["close-when-done"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then - sock:close() - return 1 - else return sock:send(chunk) end - end - }) -end - -sinkt["keep-open"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if chunk then return sock:send(chunk) - else return 1 end - end - }) -end - -sinkt["default"] = sinkt["keep-open"] - -_M.sink = _M.choose(sinkt) - -sourcet["by-length"] = function(sock, length) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if length <= 0 then return nil end - local size = math.min(socket.BLOCKSIZE, length) - local chunk, err = sock:receive(size) - if err then return nil, err end - length = length - string.len(chunk) - return chunk - end - }) -end - -sourcet["until-closed"] = function(sock) - local done - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if done then return nil end - local chunk, err, partial = sock:receive(socket.BLOCKSIZE) - if not err then return chunk - elseif err == "closed" then - sock:close() - done = 1 - return partial - else return nil, err end - end - }) -end - - -sourcet["default"] = sourcet["until-closed"] - -_M.source = _M.choose(sourcet) - -return _M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/ftp.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/ftp.lua deleted file mode 100644 index ea1145b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/ftp.lua +++ /dev/null @@ -1,285 +0,0 @@ ------------------------------------------------------------------------------ --- FTP support for the Lua language --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local table = require("table") -local string = require("string") -local math = require("math") -local socket = require("socket") -local url = require("socket.url") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -socket.ftp = {} -local _M = socket.ftp ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout in seconds before the program gives up on a connection -_M.TIMEOUT = 60 --- default port for ftp service -_M.PORT = 21 --- this is the default anonymous password. used when no password is --- provided in url. should be changed to your e-mail. -_M.USER = "ftp" -_M.PASSWORD = "anonymous@anonymous.org" - ------------------------------------------------------------------------------ --- Low level FTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function _M.open(server, port, create) - local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create)) - local f = base.setmetatable({ tp = tp }, metat) - -- make sure everything gets closed in an exception - f.try = socket.newtry(function() f:close() end) - return f -end - -function metat.__index:portconnect() - self.try(self.server:settimeout(_M.TIMEOUT)) - self.data = self.try(self.server:accept()) - self.try(self.data:settimeout(_M.TIMEOUT)) -end - -function metat.__index:pasvconnect() - self.data = self.try(socket.tcp()) - self.try(self.data:settimeout(_M.TIMEOUT)) - self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) -end - -function metat.__index:login(user, password) - self.try(self.tp:command("user", user or _M.USER)) - local code, reply = self.try(self.tp:check{"2..", 331}) - if code == 331 then - self.try(self.tp:command("pass", password or _M.PASSWORD)) - self.try(self.tp:check("2..")) - end - return 1 -end - -function metat.__index:pasv() - self.try(self.tp:command("pasv")) - local code, reply = self.try(self.tp:check("2..")) - local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" - local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) - self.try(a and b and c and d and p1 and p2, reply) - self.pasvt = { - ip = string.format("%d.%d.%d.%d", a, b, c, d), - port = p1*256 + p2 - } - if self.server then - self.server:close() - self.server = nil - end - return self.pasvt.ip, self.pasvt.port -end - -function metat.__index:port(ip, port) - self.pasvt = nil - if not ip then - ip, port = self.try(self.tp:getcontrol():getsockname()) - self.server = self.try(socket.bind(ip, 0)) - ip, port = self.try(self.server:getsockname()) - self.try(self.server:settimeout(_M.TIMEOUT)) - end - local pl = math.mod(port, 256) - local ph = (port - pl)/256 - local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") - self.try(self.tp:command("port", arg)) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:send(sendt) - self.try(self.pasvt or self.server, "need port or pasv first") - -- if there is a pasvt table, we already sent a PASV command - -- we just get the data connection into self.data - if self.pasvt then self:pasvconnect() end - -- get the transfer argument and command - local argument = sendt.argument or - url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = sendt.command or "stor" - -- send the transfer command and check the reply - self.try(self.tp:command(command, argument)) - local code, reply = self.try(self.tp:check{"2..", "1.."}) - -- if there is not a a pasvt table, then there is a server - -- and we already sent a PORT command - if not self.pasvt then self:portconnect() end - -- get the sink, source and step for the transfer - local step = sendt.step or ltn12.pump.step - local readt = {self.tp.c} - local checkstep = function(src, snk) - -- check status in control connection while downloading - local readyt = socket.select(readt, nil, 0) - if readyt[tp] then code = self.try(self.tp:check("2..")) end - return step(src, snk) - end - local sink = socket.sink("close-when-done", self.data) - -- transfer all data and check error - self.try(ltn12.pump.all(sendt.source, sink, checkstep)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - -- done with data connection - self.data:close() - -- find out how many bytes were sent - local sent = socket.skip(1, self.data:getstats()) - self.data = nil - return sent -end - -function metat.__index:receive(recvt) - self.try(self.pasvt or self.server, "need port or pasv first") - if self.pasvt then self:pasvconnect() end - local argument = recvt.argument or - url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = recvt.command or "retr" - self.try(self.tp:command(command, argument)) - local code,reply = self.try(self.tp:check{"1..", "2.."}) - if (code >= 200) and (code <= 299) then - recvt.sink(reply) - return 1 - end - if not self.pasvt then self:portconnect() end - local source = socket.source("until-closed", self.data) - local step = recvt.step or ltn12.pump.step - self.try(ltn12.pump.all(source, recvt.sink, step)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - self.data:close() - self.data = nil - return 1 -end - -function metat.__index:cwd(dir) - self.try(self.tp:command("cwd", dir)) - self.try(self.tp:check(250)) - return 1 -end - -function metat.__index:type(type) - self.try(self.tp:command("type", type)) - self.try(self.tp:check(200)) - return 1 -end - -function metat.__index:greet() - local code = self.try(self.tp:check{"1..", "2.."}) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - return 1 -end - -function metat.__index:quit() - self.try(self.tp:command("quit")) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:close() - if self.data then self.data:close() end - if self.server then self.server:close() end - return self.tp:close() -end - ------------------------------------------------------------------------------ --- High level FTP API ------------------------------------------------------------------------------ -local function override(t) - if t.url then - local u = url.parse(t.url) - for i,v in base.pairs(t) do - u[i] = v - end - return u - else return t end -end - -local function tput(putt) - putt = override(putt) - socket.try(putt.host, "missing hostname") - local f = _M.open(putt.host, putt.port, putt.create) - f:greet() - f:login(putt.user, putt.password) - if putt.type then f:type(putt.type) end - f:pasv() - local sent = f:send(putt) - f:quit() - f:close() - return sent -end - -local default = { - path = "/", - scheme = "ftp" -} - -local function parse(u) - local t = socket.try(url.parse(u, default)) - socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") - socket.try(t.host, "missing hostname") - local pat = "^type=(.)$" - if t.params then - t.type = socket.skip(2, string.find(t.params, pat)) - socket.try(t.type == "a" or t.type == "i", - "invalid type '" .. t.type .. "'") - end - return t -end - -local function sput(u, body) - local putt = parse(u) - putt.source = ltn12.source.string(body) - return tput(putt) -end - -_M.put = socket.protect(function(putt, body) - if base.type(putt) == "string" then return sput(putt, body) - else return tput(putt) end -end) - -local function tget(gett) - gett = override(gett) - socket.try(gett.host, "missing hostname") - local f = _M.open(gett.host, gett.port, gett.create) - f:greet() - f:login(gett.user, gett.password) - if gett.type then f:type(gett.type) end - f:pasv() - f:receive(gett) - f:quit() - return f:close() -end - -local function sget(u) - local gett = parse(u) - local t = {} - gett.sink = ltn12.sink.table(t) - tget(gett) - return table.concat(t) -end - -_M.command = socket.protect(function(cmdt) - cmdt = override(cmdt) - socket.try(cmdt.host, "missing hostname") - socket.try(cmdt.command, "missing command") - local f = open(cmdt.host, cmdt.port, cmdt.create) - f:greet() - f:login(cmdt.user, cmdt.password) - f.try(f.tp:command(cmdt.command, cmdt.argument)) - if cmdt.check then f.try(f.tp:check(cmdt.check)) end - f:quit() - return f:close() -end) - -_M.get = socket.protect(function(gett) - if base.type(gett) == "string" then return sget(gett) - else return tget(gett) end -end) - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/headers.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/headers.lua deleted file mode 100644 index 1eb8223..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/headers.lua +++ /dev/null @@ -1,104 +0,0 @@ ------------------------------------------------------------------------------ --- Canonic header field capitalization --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ -local socket = require("socket") -socket.headers = {} -local _M = socket.headers - -_M.canonic = { - ["accept"] = "Accept", - ["accept-charset"] = "Accept-Charset", - ["accept-encoding"] = "Accept-Encoding", - ["accept-language"] = "Accept-Language", - ["accept-ranges"] = "Accept-Ranges", - ["action"] = "Action", - ["alternate-recipient"] = "Alternate-Recipient", - ["age"] = "Age", - ["allow"] = "Allow", - ["arrival-date"] = "Arrival-Date", - ["authorization"] = "Authorization", - ["bcc"] = "Bcc", - ["cache-control"] = "Cache-Control", - ["cc"] = "Cc", - ["comments"] = "Comments", - ["connection"] = "Connection", - ["content-description"] = "Content-Description", - ["content-disposition"] = "Content-Disposition", - ["content-encoding"] = "Content-Encoding", - ["content-id"] = "Content-ID", - ["content-language"] = "Content-Language", - ["content-length"] = "Content-Length", - ["content-location"] = "Content-Location", - ["content-md5"] = "Content-MD5", - ["content-range"] = "Content-Range", - ["content-transfer-encoding"] = "Content-Transfer-Encoding", - ["content-type"] = "Content-Type", - ["cookie"] = "Cookie", - ["date"] = "Date", - ["diagnostic-code"] = "Diagnostic-Code", - ["dsn-gateway"] = "DSN-Gateway", - ["etag"] = "ETag", - ["expect"] = "Expect", - ["expires"] = "Expires", - ["final-log-id"] = "Final-Log-ID", - ["final-recipient"] = "Final-Recipient", - ["from"] = "From", - ["host"] = "Host", - ["if-match"] = "If-Match", - ["if-modified-since"] = "If-Modified-Since", - ["if-none-match"] = "If-None-Match", - ["if-range"] = "If-Range", - ["if-unmodified-since"] = "If-Unmodified-Since", - ["in-reply-to"] = "In-Reply-To", - ["keywords"] = "Keywords", - ["last-attempt-date"] = "Last-Attempt-Date", - ["last-modified"] = "Last-Modified", - ["location"] = "Location", - ["max-forwards"] = "Max-Forwards", - ["message-id"] = "Message-ID", - ["mime-version"] = "MIME-Version", - ["original-envelope-id"] = "Original-Envelope-ID", - ["original-recipient"] = "Original-Recipient", - ["pragma"] = "Pragma", - ["proxy-authenticate"] = "Proxy-Authenticate", - ["proxy-authorization"] = "Proxy-Authorization", - ["range"] = "Range", - ["received"] = "Received", - ["received-from-mta"] = "Received-From-MTA", - ["references"] = "References", - ["referer"] = "Referer", - ["remote-mta"] = "Remote-MTA", - ["reply-to"] = "Reply-To", - ["reporting-mta"] = "Reporting-MTA", - ["resent-bcc"] = "Resent-Bcc", - ["resent-cc"] = "Resent-Cc", - ["resent-date"] = "Resent-Date", - ["resent-from"] = "Resent-From", - ["resent-message-id"] = "Resent-Message-ID", - ["resent-reply-to"] = "Resent-Reply-To", - ["resent-sender"] = "Resent-Sender", - ["resent-to"] = "Resent-To", - ["retry-after"] = "Retry-After", - ["return-path"] = "Return-Path", - ["sender"] = "Sender", - ["server"] = "Server", - ["smtp-remote-recipient"] = "SMTP-Remote-Recipient", - ["status"] = "Status", - ["subject"] = "Subject", - ["te"] = "TE", - ["to"] = "To", - ["trailer"] = "Trailer", - ["transfer-encoding"] = "Transfer-Encoding", - ["upgrade"] = "Upgrade", - ["user-agent"] = "User-Agent", - ["vary"] = "Vary", - ["via"] = "Via", - ["warning"] = "Warning", - ["will-retry-until"] = "Will-Retry-Until", - ["www-authenticate"] = "WWW-Authenticate", - ["x-mailer"] = "X-Mailer", -} - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/http.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/http.lua deleted file mode 100644 index ac4b2d6..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/http.lua +++ /dev/null @@ -1,354 +0,0 @@ ------------------------------------------------------------------------------ --- HTTP/1.1 client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies -------------------------------------------------------------------------------- -local socket = require("socket") -local url = require("socket.url") -local ltn12 = require("ltn12") -local mime = require("mime") -local string = require("string") -local headers = require("socket.headers") -local base = _G -local table = require("table") -socket.http = {} -local _M = socket.http - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- connection timeout in seconds -TIMEOUT = 60 --- default port for document retrieval -_M.PORT = 80 --- user agent field sent in request -_M.USERAGENT = socket._VERSION - ------------------------------------------------------------------------------ --- Reads MIME headers from a connection, unfolding where needed ------------------------------------------------------------------------------ -local function receiveheaders(sock, headers) - local line, name, value, err - headers = headers or {} - -- get first line - line, err = sock:receive() - if err then return nil, err end - -- headers go until a blank line is found - while line ~= "" do - -- get field-name and value - name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) - if not (name and value) then return nil, "malformed reponse headers" end - name = string.lower(name) - -- get next line (value might be folded) - line, err = sock:receive() - if err then return nil, err end - -- unfold any folded values - while string.find(line, "^%s") do - value = value .. line - line = sock:receive() - if err then return nil, err end - end - -- save pair in table - if headers[name] then headers[name] = headers[name] .. ", " .. value - else headers[name] = value end - end - return headers -end - ------------------------------------------------------------------------------ --- Extra sources and sinks ------------------------------------------------------------------------------ -socket.sourcet["http-chunked"] = function(sock, headers) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - -- get chunk size, skip extention - local line, err = sock:receive() - if err then return nil, err end - local size = base.tonumber(string.gsub(line, ";.*", ""), 16) - if not size then return nil, "invalid chunk size" end - -- was it the last chunk? - if size > 0 then - -- if not, get chunk and skip terminating CRLF - local chunk, err, part = sock:receive(size) - if chunk then sock:receive() end - return chunk, err - else - -- if it was, read trailers into headers table - headers, err = receiveheaders(sock, headers) - if not headers then return nil, err end - end - end - }) -end - -socket.sinkt["http-chunked"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then return sock:send("0\r\n\r\n") end - local size = string.format("%X\r\n", string.len(chunk)) - return sock:send(size .. chunk .. "\r\n") - end - }) -end - ------------------------------------------------------------------------------ --- Low level HTTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function _M.open(host, port, create) - -- create socket with user connect function, or with default - local c = socket.try((create or socket.tcp)()) - local h = base.setmetatable({ c = c }, metat) - -- create finalized try - h.try = socket.newtry(function() h:close() end) - -- set timeout before connecting - h.try(c:settimeout(_M.TIMEOUT)) - h.try(c:connect(host, port or _M.PORT)) - -- here everything worked - return h -end - -function metat.__index:sendrequestline(method, uri) - local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) - return self.try(self.c:send(reqline)) -end - -function metat.__index:sendheaders(tosend) - local canonic = headers.canonic - local h = "\r\n" - for f, v in base.pairs(tosend) do - h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h - end - self.try(self.c:send(h)) - return 1 -end - -function metat.__index:sendbody(headers, source, step) - source = source or ltn12.source.empty() - step = step or ltn12.pump.step - -- if we don't know the size in advance, send chunked and hope for the best - local mode = "http-chunked" - if headers["content-length"] then mode = "keep-open" end - return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) -end - -function metat.__index:receivestatusline() - local status = self.try(self.c:receive(5)) - -- identify HTTP/0.9 responses, which do not contain a status line - -- this is just a heuristic, but is what the RFC recommends - if status ~= "HTTP/" then return nil, status end - -- otherwise proceed reading a status line - status = self.try(self.c:receive("*l", status)) - local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) - return self.try(base.tonumber(code), status) -end - -function metat.__index:receiveheaders() - return self.try(receiveheaders(self.c)) -end - -function metat.__index:receivebody(headers, sink, step) - sink = sink or ltn12.sink.null() - step = step or ltn12.pump.step - local length = base.tonumber(headers["content-length"]) - local t = headers["transfer-encoding"] -- shortcut - local mode = "default" -- connection close - if t and t ~= "identity" then mode = "http-chunked" - elseif base.tonumber(headers["content-length"]) then mode = "by-length" end - return self.try(ltn12.pump.all(socket.source(mode, self.c, length), - sink, step)) -end - -function metat.__index:receive09body(status, sink, step) - local source = ltn12.source.rewind(socket.source("until-closed", self.c)) - source(status) - return self.try(ltn12.pump.all(source, sink, step)) -end - -function metat.__index:close() - return self.c:close() -end - ------------------------------------------------------------------------------ --- High level HTTP API ------------------------------------------------------------------------------ -local function adjusturi(reqt) - local u = reqt - -- if there is a proxy, we need the full url. otherwise, just a part. - if not reqt.proxy and not PROXY then - u = { - path = socket.try(reqt.path, "invalid path 'nil'"), - params = reqt.params, - query = reqt.query, - fragment = reqt.fragment - } - end - return url.build(u) -end - -local function adjustproxy(reqt) - local proxy = reqt.proxy or PROXY - if proxy then - proxy = url.parse(proxy) - return proxy.host, proxy.port or 3128 - else - return reqt.host, reqt.port - end -end - -local function adjustheaders(reqt) - -- default headers - local lower = { - ["user-agent"] = _M.USERAGENT, - ["host"] = reqt.host, - ["connection"] = "close, TE", - ["te"] = "trailers" - } - -- if we have authentication information, pass it along - if reqt.user and reqt.password then - lower["authorization"] = - "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) - end - -- override with user headers - for i,v in base.pairs(reqt.headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - --- default url parts -local default = { - host = "", - port = _M.PORT, - path ="/", - scheme = "http" -} - -local function adjustrequest(reqt) - -- parse url if provided - local nreqt = reqt.url and url.parse(reqt.url, default) or {} - -- explicit components override url - for i,v in base.pairs(reqt) do nreqt[i] = v end - if nreqt.port == "" then nreqt.port = 80 end - socket.try(nreqt.host and nreqt.host ~= "", - "invalid host '" .. base.tostring(nreqt.host) .. "'") - -- compute uri if user hasn't overriden - nreqt.uri = reqt.uri or adjusturi(nreqt) - -- ajust host and port if there is a proxy - nreqt.host, nreqt.port = adjustproxy(nreqt) - -- adjust headers in request - nreqt.headers = adjustheaders(nreqt) - return nreqt -end - -local function shouldredirect(reqt, code, headers) - return headers.location and - string.gsub(headers.location, "%s", "") ~= "" and - (reqt.redirect ~= false) and - (code == 301 or code == 302 or code == 303 or code == 307) and - (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") - and (not reqt.nredirects or reqt.nredirects < 5) -end - -local function shouldreceivebody(reqt, code) - if reqt.method == "HEAD" then return nil end - if code == 204 or code == 304 then return nil end - if code >= 100 and code < 200 then return nil end - return 1 -end - --- forward declarations -local trequest, tredirect - ---[[local]] function tredirect(reqt, location) - local result, code, headers, status = trequest { - -- the RFC says the redirect URL has to be absolute, but some - -- servers do not respect that - url = url.absolute(reqt.url, location), - source = reqt.source, - sink = reqt.sink, - headers = reqt.headers, - proxy = reqt.proxy, - nredirects = (reqt.nredirects or 0) + 1, - create = reqt.create - } - -- pass location header back as a hint we redirected - headers = headers or {} - headers.location = headers.location or location - return result, code, headers, status -end - ---[[local]] function trequest(reqt) - -- we loop until we get what we want, or - -- until we are sure there is no way to get it - local nreqt = adjustrequest(reqt) - local h = _M.open(nreqt.host, nreqt.port, nreqt.create) - -- send request line and headers - h:sendrequestline(nreqt.method, nreqt.uri) - h:sendheaders(nreqt.headers) - -- if there is a body, send it - if nreqt.source then - h:sendbody(nreqt.headers, nreqt.source, nreqt.step) - end - local code, status = h:receivestatusline() - -- if it is an HTTP/0.9 server, simply get the body and we are done - if not code then - h:receive09body(status, nreqt.sink, nreqt.step) - return 1, 200 - end - local headers - -- ignore any 100-continue messages - while code == 100 do - headers = h:receiveheaders() - code, status = h:receivestatusline() - end - headers = h:receiveheaders() - -- at this point we should have a honest reply from the server - -- we can't redirect if we already used the source, so we report the error - if shouldredirect(nreqt, code, headers) and not nreqt.source then - h:close() - return tredirect(reqt, headers.location) - end - -- here we are finally done - if shouldreceivebody(nreqt, code) then - h:receivebody(headers, nreqt.sink, nreqt.step) - end - h:close() - return 1, code, headers, status -end - -local function srequest(u, b) - local t = {} - local reqt = { - url = u, - sink = ltn12.sink.table(t) - } - if b then - reqt.source = ltn12.source.string(b) - reqt.headers = { - ["content-length"] = string.len(b), - ["content-type"] = "application/x-www-form-urlencoded" - } - reqt.method = "POST" - end - local code, headers, status = socket.skip(1, trequest(reqt)) - return table.concat(t), code, headers, status -end - -_M.request = socket.protect(function(reqt, body) - if base.type(reqt) == "string" then return srequest(reqt, body) - else return trequest(reqt) end -end) - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/smtp.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/smtp.lua deleted file mode 100644 index b113d00..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/smtp.lua +++ /dev/null @@ -1,256 +0,0 @@ ------------------------------------------------------------------------------ --- SMTP client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local coroutine = require("coroutine") -local string = require("string") -local math = require("math") -local os = require("os") -local socket = require("socket") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -local headers = require("socket.headers") -local mime = require("mime") - -socket.smtp = {} -local _M = socket.smtp - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout for connection -_M.TIMEOUT = 60 --- default server used to send e-mails -_M.SERVER = "localhost" --- default port -_M.PORT = 25 --- domain used in HELO command and default sendmail --- If we are under a CGI, try to get from environment -_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost" --- default time zone (means we don't know) -_M.ZONE = "-0000" - ---------------------------------------------------------------------------- --- Low level SMTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function metat.__index:greet(domain) - self.try(self.tp:check("2..")) - self.try(self.tp:command("EHLO", domain or _M.DOMAIN)) - return socket.skip(1, self.try(self.tp:check("2.."))) -end - -function metat.__index:mail(from) - self.try(self.tp:command("MAIL", "FROM:" .. from)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:rcpt(to) - self.try(self.tp:command("RCPT", "TO:" .. to)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:data(src, step) - self.try(self.tp:command("DATA")) - self.try(self.tp:check("3..")) - self.try(self.tp:source(src, step)) - self.try(self.tp:send("\r\n.\r\n")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:quit() - self.try(self.tp:command("QUIT")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:close() - return self.tp:close() -end - -function metat.__index:login(user, password) - self.try(self.tp:command("AUTH", "LOGIN")) - self.try(self.tp:check("3..")) - self.try(self.tp:send(mime.b64(user) .. "\r\n")) - self.try(self.tp:check("3..")) - self.try(self.tp:send(mime.b64(password) .. "\r\n")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:plain(user, password) - local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) - self.try(self.tp:command("AUTH", auth)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:auth(user, password, ext) - if not user or not password then return 1 end - if string.find(ext, "AUTH[^\n]+LOGIN") then - return self:login(user, password) - elseif string.find(ext, "AUTH[^\n]+PLAIN") then - return self:plain(user, password) - else - self.try(nil, "authentication not supported") - end -end - --- send message or throw an exception -function metat.__index:send(mailt) - self:mail(mailt.from) - if base.type(mailt.rcpt) == "table" then - for i,v in base.ipairs(mailt.rcpt) do - self:rcpt(v) - end - else - self:rcpt(mailt.rcpt) - end - self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) -end - -function _M.open(server, port, create) - local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT, - _M.TIMEOUT, create)) - local s = base.setmetatable({tp = tp}, metat) - -- make sure tp is closed if we get an exception - s.try = socket.newtry(function() - s:close() - end) - return s -end - --- convert headers to lowercase -local function lower_headers(headers) - local lower = {} - for i,v in base.pairs(headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - ---------------------------------------------------------------------------- --- Multipart message source ------------------------------------------------------------------------------ --- returns a hopefully unique mime boundary -local seqno = 0 -local function newboundary() - seqno = seqno + 1 - return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), - math.random(0, 99999), seqno) -end - --- send_message forward declaration -local send_message - --- yield the headers all at once, it's faster -local function send_headers(tosend) - local canonic = headers.canonic - local h = "\r\n" - for f,v in base.pairs(tosend) do - h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h - end - coroutine.yield(h) -end - --- yield multipart message body from a multipart message table -local function send_multipart(mesgt) - -- make sure we have our boundary and send headers - local bd = newboundary() - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or 'multipart/mixed' - headers['content-type'] = headers['content-type'] .. - '; boundary="' .. bd .. '"' - send_headers(headers) - -- send preamble - if mesgt.body.preamble then - coroutine.yield(mesgt.body.preamble) - coroutine.yield("\r\n") - end - -- send each part separated by a boundary - for i, m in base.ipairs(mesgt.body) do - coroutine.yield("\r\n--" .. bd .. "\r\n") - send_message(m) - end - -- send last boundary - coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") - -- send epilogue - if mesgt.body.epilogue then - coroutine.yield(mesgt.body.epilogue) - coroutine.yield("\r\n") - end -end - --- yield message body from a source -local function send_source(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from source - while true do - local chunk, err = mesgt.body() - if err then coroutine.yield(nil, err) - elseif chunk then coroutine.yield(chunk) - else break end - end -end - --- yield message body from a string -local function send_string(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from string - coroutine.yield(mesgt.body) -end - --- message source -function send_message(mesgt) - if base.type(mesgt.body) == "table" then send_multipart(mesgt) - elseif base.type(mesgt.body) == "function" then send_source(mesgt) - else send_string(mesgt) end -end - --- set defaul headers -local function adjust_headers(mesgt) - local lower = lower_headers(mesgt.headers) - lower["date"] = lower["date"] or - os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE) - lower["x-mailer"] = lower["x-mailer"] or socket._VERSION - -- this can't be overriden - lower["mime-version"] = "1.0" - return lower -end - -function _M.message(mesgt) - mesgt.headers = adjust_headers(mesgt) - -- create and return message source - local co = coroutine.create(function() send_message(mesgt) end) - return function() - local ret, a, b = coroutine.resume(co) - if ret then return a, b - else return nil, a end - end -end - ---------------------------------------------------------------------------- --- High level SMTP API ------------------------------------------------------------------------------ -_M.send = socket.protect(function(mailt) - local s = _M.open(mailt.server, mailt.port, mailt.create) - local ext = s:greet(mailt.domain) - s:auth(mailt.user, mailt.password, ext) - s:send(mailt) - s:quit() - return s:close() -end) - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/tp.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/tp.lua deleted file mode 100644 index cbeff56..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/tp.lua +++ /dev/null @@ -1,126 +0,0 @@ ------------------------------------------------------------------------------ --- Unified SMTP/FTP subsystem --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local socket = require("socket") -local ltn12 = require("ltn12") - -socket.tp = {} -local _M = socket.tp - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ -_M.TIMEOUT = 60 - ------------------------------------------------------------------------------ --- Implementation ------------------------------------------------------------------------------ --- gets server reply (works for SMTP and FTP) -local function get_reply(c) - local code, current, sep - local line, err = c:receive() - local reply = line - if err then return nil, err end - code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - if not code then return nil, "invalid server reply" end - if sep == "-" then -- reply is multiline - repeat - line, err = c:receive() - if err then return nil, err end - current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - reply = reply .. "\n" .. line - -- reply ends with same code - until code == current and sep == " " - end - return code, reply -end - --- metatable for sock object -local metat = { __index = {} } - -function metat.__index:check(ok) - local code, reply = get_reply(self.c) - if not code then return nil, reply end - if base.type(ok) ~= "function" then - if base.type(ok) == "table" then - for i, v in base.ipairs(ok) do - if string.find(code, v) then - return base.tonumber(code), reply - end - end - return nil, reply - else - if string.find(code, ok) then return base.tonumber(code), reply - else return nil, reply end - end - else return ok(base.tonumber(code), reply) end -end - -function metat.__index:command(cmd, arg) - cmd = string.upper(cmd) - if arg then - return self.c:send(cmd .. " " .. arg.. "\r\n") - else - return self.c:send(cmd .. "\r\n") - end -end - -function metat.__index:sink(snk, pat) - local chunk, err = c:receive(pat) - return snk(chunk, err) -end - -function metat.__index:send(data) - return self.c:send(data) -end - -function metat.__index:receive(pat) - return self.c:receive(pat) -end - -function metat.__index:getfd() - return self.c:getfd() -end - -function metat.__index:dirty() - return self.c:dirty() -end - -function metat.__index:getcontrol() - return self.c -end - -function metat.__index:source(source, step) - local sink = socket.sink("keep-open", self.c) - local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) - return ret, err -end - --- closes the underlying c -function metat.__index:close() - self.c:close() - return 1 -end - --- connect with server and return c object -function _M.connect(host, port, timeout, create) - local c, e = (create or socket.tcp)() - if not c then return nil, e end - c:settimeout(timeout or _M.TIMEOUT) - local r, e = c:connect(host, port) - if not r then - c:close() - return nil, e - end - return base.setmetatable({c = c}, metat) -end - -return _M \ No newline at end of file diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/url.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/url.lua deleted file mode 100644 index 7809535..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/socket/url.lua +++ /dev/null @@ -1,307 +0,0 @@ ------------------------------------------------------------------------------ --- URI parsing, composition and relative URL resolution --- LuaSocket toolkit. --- Author: Diego Nehab ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local base = _G -local table = require("table") -local socket = require("socket") - -socket.url = {} -local _M = socket.url - ------------------------------------------------------------------------------ --- Module version ------------------------------------------------------------------------------ -_M._VERSION = "URL 1.0.3" - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function _M.escape(s) - return (string.gsub(s, "([^A-Za-z0-9_])", function(c) - return string.format("%%%02x", string.byte(c)) - end)) -end - ------------------------------------------------------------------------------ --- Protects a path segment, to prevent it from interfering with the --- url parsing. --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -local function make_set(t) - local s = {} - for i,v in base.ipairs(t) do - s[t[i]] = 1 - end - return s -end - --- these are allowed withing a path segment, along with alphanum --- other characters must be escaped -local segment_set = make_set { - "-", "_", ".", "!", "~", "*", "'", "(", - ")", ":", "@", "&", "=", "+", "$", ",", -} - -local function protect_segment(s) - return string.gsub(s, "([^A-Za-z0-9_])", function (c) - if segment_set[c] then return c - else return string.format("%%%02x", string.byte(c)) end - end) -end - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function _M.unescape(s) - return (string.gsub(s, "%%(%x%x)", function(hex) - return string.char(base.tonumber(hex, 16)) - end)) -end - ------------------------------------------------------------------------------ --- Builds a path from a base path and a relative path --- Input --- base_path --- relative_path --- Returns --- corresponding absolute path ------------------------------------------------------------------------------ -local function absolute_path(base_path, relative_path) - if string.sub(relative_path, 1, 1) == "/" then return relative_path end - local path = string.gsub(base_path, "[^/]*$", "") - path = path .. relative_path - path = string.gsub(path, "([^/]*%./)", function (s) - if s ~= "./" then return s else return "" end - end) - path = string.gsub(path, "/%.$", "/") - local reduced - while reduced ~= path do - reduced = path - path = string.gsub(reduced, "([^/]*/%.%./)", function (s) - if s ~= "../../" then return "" else return s end - end) - end - path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) - if s ~= "../.." then return "" else return s end - end) - return path -end - ------------------------------------------------------------------------------ --- Parses a url and returns a table with all its parts according to RFC 2396 --- The following grammar describes the names given to the URL parts --- ::= :///;?# --- ::= @: --- ::= [:] --- :: = {/} --- Input --- url: uniform resource locator of request --- default: table with default values for each field --- Returns --- table with the following fields, where RFC naming conventions have --- been preserved: --- scheme, authority, userinfo, user, password, host, port, --- path, params, query, fragment --- Obs: --- the leading '/' in {/} is considered part of ------------------------------------------------------------------------------ -function _M.parse(url, default) - -- initialize default parameters - local parsed = {} - for i,v in base.pairs(default or parsed) do parsed[i] = v end - -- empty url is parsed to nil - if not url or url == "" then return nil, "invalid url" end - -- remove whitespace - -- url = string.gsub(url, "%s", "") - -- get fragment - url = string.gsub(url, "#(.*)$", function(f) - parsed.fragment = f - return "" - end) - -- get scheme - url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", - function(s) parsed.scheme = s; return "" end) - -- get authority - url = string.gsub(url, "^//([^/]*)", function(n) - parsed.authority = n - return "" - end) - -- get query string - url = string.gsub(url, "%?(.*)", function(q) - parsed.query = q - return "" - end) - -- get params - url = string.gsub(url, "%;(.*)", function(p) - parsed.params = p - return "" - end) - -- path is whatever was left - if url ~= "" then parsed.path = url end - local authority = parsed.authority - if not authority then return parsed end - authority = string.gsub(authority,"^([^@]*)@", - function(u) parsed.userinfo = u; return "" end) - authority = string.gsub(authority, ":([^:%]]*)$", - function(p) parsed.port = p; return "" end) - if authority ~= "" then - -- IPv6? - parsed.host = string.match(authority, "^%[(.+)%]$") or authority - end - local userinfo = parsed.userinfo - if not userinfo then return parsed end - userinfo = string.gsub(userinfo, ":([^:]*)$", - function(p) parsed.password = p; return "" end) - parsed.user = userinfo - return parsed -end - ------------------------------------------------------------------------------ --- Rebuilds a parsed URL from its components. --- Components are protected if any reserved or unallowed characters are found --- Input --- parsed: parsed URL, as returned by parse --- Returns --- a stringing with the corresponding URL ------------------------------------------------------------------------------ -function _M.build(parsed) - local ppath = _M.parse_path(parsed.path or "") - local url = _M.build_path(ppath) - if parsed.params then url = url .. ";" .. parsed.params end - if parsed.query then url = url .. "?" .. parsed.query end - local authority = parsed.authority - if parsed.host then - authority = parsed.host - if string.find(authority, ":") then -- IPv6? - authority = "[" .. authority .. "]" - end - if parsed.port then authority = authority .. ":" .. parsed.port end - local userinfo = parsed.userinfo - if parsed.user then - userinfo = parsed.user - if parsed.password then - userinfo = userinfo .. ":" .. parsed.password - end - end - if userinfo then authority = userinfo .. "@" .. authority end - end - if authority then url = "//" .. authority .. url end - if parsed.scheme then url = parsed.scheme .. ":" .. url end - if parsed.fragment then url = url .. "#" .. parsed.fragment end - -- url = string.gsub(url, "%s", "") - return url -end - ------------------------------------------------------------------------------ --- Builds a absolute URL from a base and a relative URL according to RFC 2396 --- Input --- base_url --- relative_url --- Returns --- corresponding absolute url ------------------------------------------------------------------------------ -function _M.absolute(base_url, relative_url) - if base.type(base_url) == "table" then - base_parsed = base_url - base_url = _M.build(base_parsed) - else - base_parsed = _M.parse(base_url) - end - local relative_parsed = _M.parse(relative_url) - if not base_parsed then return relative_url - elseif not relative_parsed then return base_url - elseif relative_parsed.scheme then return relative_url - else - relative_parsed.scheme = base_parsed.scheme - if not relative_parsed.authority then - relative_parsed.authority = base_parsed.authority - if not relative_parsed.path then - relative_parsed.path = base_parsed.path - if not relative_parsed.params then - relative_parsed.params = base_parsed.params - if not relative_parsed.query then - relative_parsed.query = base_parsed.query - end - end - else - relative_parsed.path = absolute_path(base_parsed.path or "", - relative_parsed.path) - end - end - return _M.build(relative_parsed) - end -end - ------------------------------------------------------------------------------ --- Breaks a path into its segments, unescaping the segments --- Input --- path --- Returns --- segment: a table with one entry per segment ------------------------------------------------------------------------------ -function _M.parse_path(path) - local parsed = {} - path = path or "" - --path = string.gsub(path, "%s", "") - string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) - for i = 1, #parsed do - parsed[i] = _M.unescape(parsed[i]) - end - if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end - if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end - return parsed -end - ------------------------------------------------------------------------------ --- Builds a path component from its segments, escaping protected characters. --- Input --- parsed: path segments --- unsafe: if true, segments are not protected before path is built --- Returns --- path: corresponding path stringing ------------------------------------------------------------------------------ -function _M.build_path(parsed, unsafe) - local path = "" - local n = #parsed - if unsafe then - for i = 1, n-1 do - path = path .. parsed[i] - path = path .. "/" - end - if n > 0 then - path = path .. parsed[n] - if parsed.is_directory then path = path .. "/" end - end - else - for i = 1, n-1 do - path = path .. protect_segment(parsed[i]) - path = path .. "/" - end - if n > 0 then - path = path .. protect_segment(parsed[n]) - if parsed.is_directory then path = path .. "/" end - end - end - if parsed.is_absolute then path = "/" .. path end - return path -end - -return _M diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl.lua deleted file mode 100644 index 0170bc8..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl.lua +++ /dev/null @@ -1,93 +0,0 @@ ------------------------------------------------------------------------------- --- LuaSec 0.4.1 --- Copyright (C) 2006-2011 Bruno Silvestre --- ------------------------------------------------------------------------------- - -module("ssl", package.seeall) - -require("ssl.core") -require("ssl.context") - - -_VERSION = "0.4.1" -_COPYRIGHT = "LuaSec 0.4.1 - Copyright (C) 2006-2011 Bruno Silvestre\n" .. - "LuaSocket 2.0.2 - Copyright (C) 2004-2007 Diego Nehab" - --- Export functions -rawconnection = core.rawconnection -rawcontext = context.rawcontext - --- --- --- -local function optexec(func, param, ctx) - if param then - if type(param) == "table" then - return func(ctx, unpack(param)) - else - return func(ctx, param) - end - end - return true -end - --- --- --- -function newcontext(cfg) - local succ, msg, ctx - -- Create the context - ctx, msg = context.create(cfg.protocol) - if not ctx then return nil, msg end - -- Mode - succ, msg = context.setmode(ctx, cfg.mode) - if not succ then return nil, msg end - -- Load the key - if cfg.key then - succ, msg = context.loadkey(ctx, cfg.key, cfg.password) - if not succ then return nil, msg end - end - -- Load the certificate - if cfg.certificate then - succ, msg = context.loadcert(ctx, cfg.certificate) - if not succ then return nil, msg end - end - -- Load the CA certificates - if cfg.cafile or cfg.capath then - succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) - if not succ then return nil, msg end - end - -- Set the verification options - succ, msg = optexec(context.setverify, cfg.verify, ctx) - if not succ then return nil, msg end - -- Set SSL options - succ, msg = optexec(context.setoptions, cfg.options, ctx) - if not succ then return nil, msg end - -- Set the depth for certificate verification - if cfg.depth then - succ, msg = context.setdepth(ctx, cfg.depth) - if not succ then return nil, msg end - end - return ctx -end - --- --- --- -function wrap(sock, cfg) - local ctx, msg - if type(cfg) == "table" then - ctx, msg = newcontext(cfg) - if not ctx then return nil, msg end - else - ctx = cfg - end - local s, msg = core.create(ctx) - if s then - core.setfd(s, sock:getfd()) - sock:setfd(core.invalidfd) - return s - end - return nil, msg -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl/https.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl/https.lua deleted file mode 100644 index 00a7e5b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/ssl/https.lua +++ /dev/null @@ -1,138 +0,0 @@ ----------------------------------------------------------------------------- --- LuaSec 0.4.1 --- Copyright (C) 2009-2011 PUC-Rio --- --- Author: Pablo Musa --- Author: Tomas Guisasola ---------------------------------------------------------------------------- - -local socket = require("socket") -local ssl = require("ssl") -local ltn12 = require("ltn12") -local http = require("socket.http") -local url = require("socket.url") - -local table = require("table") -local string = require("string") - -local try = socket.try -local type = type -local pairs = pairs -local getmetatable = getmetatable - -module("ssl.https") - -_VERSION = "0.4.1" -_COPYRIGHT = "LuaSec 0.4.1 - Copyright (C) 2009-2011 PUC-Rio" - --- Default settings -PORT = 443 - -local cfg = { - protocol = "tlsv1", - options = "all", - verify = "none", -} - --------------------------------------------------------------------- --- Auxiliar Functions --------------------------------------------------------------------- - --- Insert default HTTPS port. -local function default_https_port(u) - return url.build(url.parse(u, {port = PORT})) -end - --- Convert an URL to a table according to Luasocket needs. -local function urlstring_totable(url, body, result_table) - url = { - url = default_https_port(url), - method = body and "POST" or "GET", - sink = ltn12.sink.table(result_table) - } - if body then - url.source = ltn12.source.string(body) - url.headers = { - ["content-length"] = #body, - ["content-type"] = "application/x-www-form-urlencoded", - } - end - return url -end - --- Forward calls to the real connection object. -local function reg(conn) - local mt = getmetatable(conn.sock).__index - for name, method in pairs(mt) do - if type(method) == "function" then - conn[name] = function (self, ...) - return method(self.sock, ...) - end - end - end -end - --- Return a function which performs the SSL/TLS connection. -local function tcp(params) - params = params or {} - -- Default settings - for k, v in pairs(cfg) do - params[k] = params[k] or v - end - -- Force client mode - params.mode = "client" - -- 'create' function for LuaSocket - return function () - local conn = {} - conn.sock = try(socket.tcp()) - local st = getmetatable(conn.sock).__index.settimeout - function conn:settimeout(...) - return st(self.sock, ...) - end - -- Replace TCP's connection function - function conn:connect(host, port) - try(self.sock:connect(host, port)) - self.sock = try(ssl.wrap(self.sock, params)) - try(self.sock:dohandshake()) - reg(self, getmetatable(self.sock)) - return 1 - end - return conn - end -end - --------------------------------------------------------------------- --- Main Function --------------------------------------------------------------------- - --- Make a HTTP request over secure connection. This function receives --- the same parameters of LuaSocket's HTTP module (except 'proxy' and --- 'redirect') plus LuaSec parameters. --- --- @param url mandatory (string or table) --- @param body optional (string) --- @return (string if url == string or 1), code, headers, status --- -function request(url, body) - local result_table = {} - local stringrequest = type(url) == "string" - if stringrequest then - url = urlstring_totable(url, body, result_table) - else - url.url = default_https_port(url.url) - end - if http.PROXY or url.proxy then - return nil, "proxy not supported" - elseif url.redirect then - return nil, "redirect not supported" - elseif url.create then - return nil, "create function not permitted" - end - -- New 'create' function to establish a secure connection - url.create = tcp(url) - local res, code, headers, status = http.request(url) - if res and stringrequest then - return table.concat(result_table), code, headers, status - end - return res, code, headers, status -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/testwell.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/testwell.lua deleted file mode 100644 index 8172e34..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/lualibs/testwell.lua +++ /dev/null @@ -1,315 +0,0 @@ --- --- Copyright (C) 2012 Paul Kulchenko --- A simple testing library --- Based on lua-TestMore : --- Copyright (c) 2009-2011 Francois Perrad --- This library is licensed under the terms of the MIT/X11 license, --- like Lua itself. --- - -local pairs = pairs -local tostring = tostring -local type = type -local _G = _G or _ENV - ------------------------------------------------------------ - -local tb = { - curr_test = 0, - good_test = 0, - skip_test = 0, -} - -function tb:print(...) - print(...) -end - -function tb:note(...) - self:print(...) -end - -function tb:diag(...) - local arg = {...} - for k, v in pairs(arg) do - arg[k] = tostring(v) - end - local msg = table.concat(arg) - msg = msg:gsub("\n", "\n# ") - msg = msg:gsub("\n# \n", "\n#\n") - msg = msg:gsub("\n# $", '') - self:print("# " .. msg) -end - -function tb:ok(test, name, more) - self.curr_test = self.curr_test + 1 - self.good_test = self.good_test + (test and 1 or 0) - self.skip_test = self.skip_test + (test == nil and 1 or 0) - name = tostring(name or '') - local out = '' - if not test then - out = "not " - end - out = out .. "ok " .. self.curr_test - if name ~= '' then - out = out .. " - " .. name - end - self:print(out) - if test == false then - self:diag(" Failed test " .. (name and ("'" .. name .. "'") or '')) - if debug then - local info = debug.getinfo(3) - local file = info.short_src - local line = info.currentline - self:diag(" in " .. file .. " at line " .. line .. ".") - end - self:diag(more) - end -end - -function tb:done_testing(reset) - local c, g, s = self.curr_test, self.good_test, self.skip_test - if reset then - self.curr_test = 0 - self.good_test = 0 - self.skip_test = 0 - end - return c, g, s -end - ------------------------------------------------------------ - -local serpent = (function() ---- include Serpent module for serialization -local n, v = "serpent", 0.15 -- (C) 2012 Paul Kulchenko; MIT License -local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types" -local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} -local badtype = {thread = true, userdata = true} -local keyword, globals, G = {}, {}, (_G or _ENV) -for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', - 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', - 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end -for k,v in pairs(G) do globals[v] = k end -- build func to name mapping -for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do - for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end - -local function s(t, opts) - local name, indent, fatal = opts.name, opts.indent, opts.fatal - local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge - local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) - local comm = opts.comment and (tonumber(opts.comment) or math.huge) - local seen, sref, syms, symn = {}, {}, {}, 0 - local function gensym(val) return tostring(val):gsub("[^%w]",""):gsub("(%d%w+)", - function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end) end - local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s) - or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 - or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end - local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end - local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal - and safestr(tostring(s))..comment('err',l) or error("Can't serialize "..tostring(s)) end - local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] - local n = name == nil and '' or name - local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] - local safe = plain and n or '['..safestr(n)..']' - return (path or '')..(plain and path and '.' or '')..safe, safe end - local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(o, n) - local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} - local function padnum(d) return ("%0"..maxn.."d"):format(d) end - table.sort(o, function(a,b) - return (o[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) - < (o[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end - local function val2str(t, name, indent, path, plainindex, level) - local ttype, level = type(t), (level or 0) - local spath, sname = safename(path, name) - local tag = plainindex and - ((type(name) == "number") and '' or name..space..'='..space) or - (name ~= nil and sname..space..'='..space or '') - if seen[t] then - table.insert(sref, spath..space..'='..space..seen[t]) - return tag..'nil'..comment('ref', level) - elseif badtype[ttype] then return tag..globerr(t, level) - elseif ttype == 'function' then - seen[t] = spath - local ok, res = pcall(string.dump, t) - local func = ok and ((opts.nocode and "function() end" or - "loadstring("..safestr(res)..",'@serialized')")..comment(t, level)) - return tag..(func or globerr(t, level)) - elseif ttype == "table" then - if level >= maxl then return tag..'{}'..comment('max', level) end - seen[t] = spath - if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty - local maxn, o, out = #t, {}, {} - for key = 1, maxn do table.insert(o, key) end - for key in pairs(t) do if not o[key] then table.insert(o, key) end end - if opts.sortkeys then alphanumsort(o, opts.sortkeys) end - for n, key in ipairs(o) do - local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse - if opts.ignore and opts.ignore[value] -- skip ignored values; do nothing - or sparse and value == nil then -- skipping nils; do nothing - elseif ktype == 'table' or ktype == 'function' then - if not seen[key] and not globals[key] then - table.insert(sref, 'local '..val2str(key,gensym(key),indent)) end - table.insert(sref, seen[t]..'['..(seen[key] or globals[key] or gensym(key)) - ..']'..space..'='..space..(seen[value] or val2str(value,nil,indent))) - else - if badtype[ktype] then plainindex, key = true, '['..globerr(key, level+1)..']' end - table.insert(out,val2str(value,key,indent,spath,plainindex,level+1)) - end - end - local prefix = string.rep(indent or '', level) - local head = indent and '{\n'..prefix..indent or '{' - local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) - local tail = indent and "\n"..prefix..'}' or '}' - return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level) - else return tag..safestr(t) end -- handle all other types - end - local sepr = indent and "\n" or ";"..space - local body = val2str(t, name, indent) -- this call also populates sref - local tail = #sref>0 and table.concat(sref, sepr)..sepr or '' - return not name and body or "do local "..body..sepr..tail.."return "..name..sepr.."end" -end - -local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end -return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, - dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, - line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, - block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } -end)() ---- end of Serpent module - ------------------------------------------------------------ - -local m = {} - -function m.ok(test, name) - tb:ok(test, name) -end - -local parms = {comment = false} -function m.is(got, expected, name) - local tgot, texp = type(got), type(expected) - local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms) - local pass = vgot == vexp - if got == nil then pass = nil end - tb:ok(pass, name, not pass and - " got: " .. vgot .. " (" .. tgot .. ")" .. - "\n expected: " .. vexp .. " (" .. texp .. ")") -end - -function m.isnt(got, expected, name) - local tgot, texp = type(got), type(expected) - local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms) - local pass = vgot ~= vexp - if got == nil then pass = nil end - tb:ok(pass, name, not pass and - " got: " .. vgot .. " (" .. tgot .. ")" .. - "\n expected: anything else") -end - -function m.like(got, pattern, name) - if type(pattern) ~= 'string' then - return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern)) - end - - local pass = tostring(got):match(pattern) - if got == nil then pass = nil end - tb:ok(pass, name, not pass and - " '" .. tostring(got) .. "'" .. - "\n doesn't match '" .. pattern .. "'") -end - -function m.unlike(got, pattern, name) - if type(pattern) ~= 'string' then - return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern)) - end - - local pass = not tostring(got):match(pattern) - if got == nil then pass = nil end - tb:ok(pass, name, not pass and - " '" .. tostring(got) .. "'" .. - "\n matches '" .. pattern .. "'") -end - -local cmp = { - ['<'] = function (a, b) return a < b end, - ['<='] = function (a, b) return a <= b end, - ['>'] = function (a, b) return a > b end, - ['>='] = function (a, b) return a >= b end, - ['=='] = function (a, b) return a == b end, - ['~='] = function (a, b) return a ~= b end, -} - -function m.cmp_ok(this, op, that, name) - local f = cmp[op] - if not f then - return tb:ok(false, name, "unknown operator : " .. tostring(op)) - end - - local pass = f(this, that) - if this == nil then pass = nil end - tb:ok(pass, name, not pass and - " " .. tostring(this) .. - "\n " .. op .. - "\n " .. tostring(that)) -end - -function m.type_ok(val, t, name) - if type(t) ~= 'string' then - return tb:ok(false, name, "type isn't a string : " .. tostring(t)) - end - - if type(val) == t then - tb:ok(true, name) - else - tb:ok(false, name, - " " .. tostring(val) .. " isn't a '" .. t .."', it's a '" .. type(val) .. "'") - end -end - -function m.diag(...) - tb:diag(...) -end - -function m.report() - local total, good, skipped = tb:done_testing(true) - if total == 0 then return end - local failed = total - good - skipped - local sum = ("(%d/%d/%d)."):format(good, skipped, total) - local num, msg = 0, "" - if good > 0 then - num, msg = good, msg .. "passed " .. good - end - if failed > 0 then - num, msg = failed, msg .. (#msg > 0 and (skipped > 0 and ", " or " and ") or "") - .. "failed " .. failed - end - if skipped > 0 then - num, msg = skipped, msg .. (#msg > 0 and ((good > 0 and failed > 0 and ',' or '') .." and ") or "") - .. "skipped " .. skipped - end - msg = ("Looks like you %s test%s of %d %s"):format(msg, (num > 1 and 's' or ''), total, sum) - if skipped == total then msg = "Looks like you skipped all tests " .. sum end - if good == total then msg = "All tests passed " .. sum end - tb:note(("1..%d # %s"):format(total, msg)) -end - -function m.ismain() - for l = 3, 64 do -- only check up to 64 level; no more needed - local info = debug.getinfo(l) - if not info then return true end - if info.func == require then return false end - end - return true -end - --- this is needed to call report() when the test object is destroyed -if _VERSION >= "Lua 5.2" then - setmetatable(m, {__gc = m.report}) -else - -- keep sentinel alive until 'm' is garbage collected - m.sentinel = newproxy(true) - getmetatable(m.sentinel).__gc = m.report -end - -for k, v in pairs(m) do -- injection - _G[k] = v -end - -return m diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/packages/sample.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/packages/sample.lua deleted file mode 100644 index 96bb660..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/packages/sample.lua +++ /dev/null @@ -1,138 +0,0 @@ -local G = ... -local id = G.ID("sample.samplemenu") - -local P = { - name = "Sample plugin", - description = "Sample plugin to demonstrate various event types.", - author = "Paul Kulchenko", -} - --- Events that are marked with "return false" can return `false` to --- abort further processing. --- For `onEditorPreSave` event it means that file saving will be aborted. --- For `onEditorPreClose` event it means that closing an editor tab will be aborted. --- For `onEditorKeyDown` event it means that the key will be "eaten". --- For `onEditorAction` event it means that the action will not be executed. --- For `onFiletreeActivate` event it means that no further processing is done. --- For `onEditorCharAdded` event it means that no further processing is done --- (but the character is still added to the editor). - -local events = { - onRegister = function(self) end, - onUnRegister = function(self) end, - onEditorLoad = function(self, editor) end, - onEditorPreClose = function(self, editor) end, -- return false - onEditorClose = function(self, editor) end, - onEditorNew = function(self, editor) end, - onEditorPreSave = function(self, editor, filepath) end, -- return false - onEditorSave = function(self, editor) end, - onEditorFocusLost = function(self, editor) end, - onEditorFocusSet = function(self, editor) end, - onEditorAction = function(self, editor, event) end, -- return false - onEditorKeyDown = function(self, editor, event) end, -- return false - onEditorCharAdded = function(self, editor, event) end, -- return false - onEditorUserlistSelection = function(self, editor, event) end, -- return false - onEditorMarkerUpdate = function(self, editor, marker, line, value) end, - onEditorUpdateUI = function(self, editor, event) end, - onEditorPainted = function(self, editor, event) end, - onEditorCallTip = function(self, editor, tip, value, eval) end, -- return false - onFiletreeActivate = function(self, tree, event, item) end, -- return false - onFiletreeLDown = function(self, tree, event, item) end, - onFiletreeRDown = function(self, tree, event, item) end, - onMenuEditor = function(self, menu, editor, event) end, - onMenuEditorTab = function(self, menu, notebook, event, index) end, - onMenuOutput = function(self, menu, editor, event) end, - onMenuConsole = function(self, menu, editor, event) end, - onMenuFiletree = function(self, menu, tree, event) end, - onMenuOutline = function(self, menu, tree, event) end, - onMenuWatch = function(self, menu, tree, event) end, - onProjectPreLoad = function(self, project) end, -- before project is changed - onProjectLoad = function(self, project) end, -- after project is changed - onProjectClose = function(self, project) end, - onInterpreterLoad = function(self, interpreter) end, - onInterpreterClose = function(self, interpreter) end, - onIdle = function(self, event) end, - onIdleOnce = function(self, event) end, - onAppFocusLost = function(self, app) end, - onAppFocusSet = function(self, app) end, - onAppLoad = function(self, app) end, - onAppClose = function(self, app) end, - onAppDone = function(self, app) end, -- the last event right before exiting -} - ---[[ Uncomment this to see event names printed in the Output window - local skipEvents = {onIdle = true, onEditorPainted = true, onEditorUpdateUI = true} - for k in pairs(events) do - if not skipEvents[k] then - P[k] = k:find("^onEditor") - and function(self, ed) - -- document can be empty for newly added documents - local doc = ide:GetDocument(ed) - DisplayOutputLn(self:GetFileName(), k, doc and doc:GetFilePath() or "new document") end - or function(self, ...) - DisplayOutputLn(self:GetFileName(), k, ...) end - end - end - - P.onMenuEditor = function(self, menu, editor, event) - local point = editor:ScreenToClient(event:GetPosition()) - pos = editor:PositionFromPointClose(point.x, point.y) - menu:Append(id, ">> Sample item; pos "..pos) - menu:Enable(id, true) - - editor:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function() DisplayOutputLn("Selected "..pos) end) - - DisplayOutputLn(self:GetFileName(), "onMenuEditor") - end - - P.onMenuEditorTab = function(self, menu, notebook, event, index) - menu:Append(id, ">> Sample item; tab "..index) - menu:Enable(id, true) - - notebook:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function() DisplayOutputLn("Selected "..index) end) - - DisplayOutputLn(self:GetFileName(), "onMenuEditorTab") - end - - P.onMenuFiletree = function(self, menu, tree, event) - local item_id = event:GetItem() - local name = tree:GetItemFullName(item_id) - menu:Append(id, ">> Sample item; name "..name) - menu:Enable(id, true) - - tree:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function() DisplayOutputLn("Selected "..name) end) - - DisplayOutputLn(self:GetFileName(), "onMenuFiletree") - end - - P.onInterpreterLoad = function(self, interpreter) - DisplayOutputLn(self:GetFileName(), "onInterpreterLoad", interpreter:GetFileName()) - end - - P.onInterpreterClose = function(self, interpreter) - DisplayOutputLn(self:GetFileName(), "onInterpreterClose", interpreter:GetFileName()) - end - - P.onEditorPreSave = function(self, editor, filepath) - if filepath and filepath:find("%.txt$") then - DisplayOutputLn(self:GetFileName(), "onEditorPreSave", "Aborted saving a .txt file") - return false - else - DisplayOutputLn(self:GetFileName(), "onEditorPreSave", filepath or "New file") - end - end - - P.onEditorCharAdded = function(self, editor, event) - DisplayOutputLn(self:GetFileName(), "onEditorCharAdded", event:GetKey()) - end - - P.onEditorKeyDown = function(self, editor, event) - DisplayOutputLn(self:GetFileName(), "onEditorKeyDown", event:GetKeyCode()) - end - ---]] - -return P diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/lua.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/lua.lua deleted file mode 100644 index 294976f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/lua.lua +++ /dev/null @@ -1,284 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local funcdef = "([A-Za-z_][A-Za-z0-9_%.%:]*)%s*" -local decindent = { - ['else'] = true, ['elseif'] = true, ['until'] = true, ['end'] = true} -local incindent = { - ['else'] = true, ['elseif'] = true, ['for'] = true, ['do'] = true, - ['if'] = true, ['repeat'] = true, ['while'] = true} -local function isfndef(str) - local l - local s,e,cap,par = string.find(str, "function%s+" .. funcdef .. "(%(.-%))") - -- try to match without brackets now, but only at the beginning of the line - if (not s) then - s,e,cap = string.find(str, "^%s*function%s+" .. funcdef) - end - -- try to match "foo = function()" - if (not s) then - s,e,cap,par = string.find(str, funcdef .. "=%s*function%s*(%(.-%))") - end - if (s) then - l = string.find(string.sub(str,1,s-1),"local%s+$") - cap = cap .. " " .. (par or "(?)") - end - return s,e,cap,l -end -local q = EscapeMagic - -local function ldoc(tx, typepatt) - local varname = "([%w_]+)" - -- == ?string, ?|T1|T2 - -- anything that follows optional "|..." is ignored - local typename = "%??"..typepatt - -- @tparam[...] - -- @param[type=] - -- @string[...] ; not handled - local t, v = tx:match("--%s*@tparam%b[]%s+"..typename.."%s+"..varname) - if not t then -- try without optional [...] part - t, v = tx:match("--%s*@tparam%s+"..typename.."%s+"..varname) - end - if not t then - t, v = tx:match("--%s*@param%s*%[type="..typename.."%]%s+"..varname) - end - return t, v -end - -return { - exts = {"lua", "rockspec", "wlua"}, - lexer = wxstc.wxSTC_LEX_LUA, - apitype = "lua", - linecomment = "--", - sep = ".:", - isdecindent = function(str) - str = str:gsub('%-%-%[=*%[.*%]=*%]',''):gsub('%-%-.*','') - -- this handles three different cases: - local term = (str:match("^%s*(%w+)%s*$") - or str:match("^%s*(elseif)[%s%(]") - or str:match("^%s*(until)[%s%(]") - or str:match("^%s*(else)%f[%W]") - ) - -- (1) 'end', 'elseif', 'else', 'until' - local match = term and decindent[term] - -- (2) 'end)', 'end}', 'end,', and 'end;' - if not term then term, match = str:match("^%s*(end)%s*([%)%}]*)%s*[,;]?") end - -- endFoo could be captured as well; filter it out - if term and str:match("^%s*(end)%w") then term = nil end - -- (3) '},', '};', '),' and ');' - if not term then match = str:match("^%s*[%)%}]+%s*[,;]?%s*$") end - - return match and 1 or 0, match and term and 1 or 0 - end, - isincindent = function(str) - -- remove "long" comments and escaped slashes (to process \' and \" below) - str = str:gsub('%-%-%[=*%[.-%]=*%]',''):gsub('\\[\\\'"]','') - while true do - local num, sep = nil, str:match("['\"]") - if not sep then break end - str, num = str:gsub(sep..".-\\"..sep,sep):gsub(sep..".-"..sep,"") - if num == 0 then break end - end - str = (str - :gsub('%[=*%[.-%]=*%]','') -- remove long strings - :gsub('%[=*%[.*','') -- remove partial long strings - :gsub('%-%-.*','') -- strip comments after strings are processed - :gsub("%b()","()") -- remove all function calls - ) - - local term = str:match("^%s*(%w+)%W*") - local terminc = term and incindent[term] and 1 or 0 - -- fix 'if' not terminated with 'then' - -- or 'then' not started with 'if' - if (term == 'if' or term == 'elseif') and not str:match("%f[%w]then%f[%W]") - or (term == 'for') and not str:match("%S%s+do%f[%W]") - or (term == 'while') and not str:match("%f[%w]do%f[%W]") then - terminc = 0 - elseif not (term == 'if' or term == 'elseif') and str:match("%f[%w]then%f[%W]") - or not (term == 'for') and str:match("%S%s+do%f[%W]") - or not (term == 'while') and str:match("%f[%w]do%f[%W]") then - terminc = 1 - end - local _, opened = str:gsub("([%{%(])", "%1") - local _, closed = str:gsub("([%}%)])", "%1") - local func = (isfndef(str) or str:match("%W+function%s*%(")) and 1 or 0 - -- ended should only be used to negate term and func effects - local anon = str:match("%W+function%s*%(.+%Wend%W") - local ended = (terminc + func > 0) and (str:match("%W+end%s*$") or anon) and 1 or 0 - - return opened - closed + func + terminc - ended - end, - marksymbols = function(code, pos, vars) - local PARSE = require 'lua_parser_loose' - local LEX = require 'lua_lexer_loose' - local lx = LEX.lexc(code, nil, pos) - return coroutine.wrap(function() - local varnext = {} - PARSE.parse_scope_resolve(lx, function(op, name, lineinfo, vars, nobreak) - if not(op == 'Id' or op == 'Statement' or op == 'Var' - or op == 'Function' or op == 'String' - or op == 'VarNext' or op == 'VarInside' or op == 'VarSelf' - or op == 'FunctionCall' or op == 'Scope' or op == 'EndScope') then - return end -- "normal" return; not interested in other events - - -- level needs to be adjusted for VarInside as it comes into scope - -- only after next block statement - local at = vars[0] and (vars[0] + (op == 'VarInside' and 1 or 0)) - if op == 'Statement' then - for _, token in pairs(varnext) do coroutine.yield(unpack(token)) end - varnext = {} - elseif op == 'VarNext' or op == 'VarInside' then - table.insert(varnext, {'Var', name, lineinfo, vars, at, nobreak}) - end - - coroutine.yield(op, name, lineinfo, vars, op == 'Function' and at-1 or at, nobreak) - end, vars) - end) - end, - - typeassigns = function(editor) - local maxlines = 48 -- scan up to this many lines back - local iscomment = editor.spec.iscomment - local assigns = {} - local endline = editor:GetCurrentLine()-1 - local line = math.max(endline-maxlines, 0) - - while (line <= endline) do - local ls = editor:PositionFromLine(line) - local tx = editor:GetLine(line) --= string - local s = bit.band(editor:GetStyleAt(ls + #tx:match("^%s*") + 2),31) - - -- check for assignments - local sep = editor.spec.sep - local varname = "([%w_][%w_"..q(sep:sub(1,1)).."]*)" - local identifier = "([%w_][%w_"..q(sep).."%s]*)" - - -- special hint - local typ, var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier) - local ldoctype, ldocvar = ldoc(tx, varname) - if var and typ then - assigns[var] = typ:gsub("%s","") - elseif ldoctype and ldocvar then - assigns[ldocvar] = ldoctype - elseif not iscomment[s] then - -- real assignments - local var,typ = tx:match("%s*"..identifier.."%s*=%s*([^;]+)") - - var = var and var:gsub("local",""):gsub("%s","") - -- handle `require` as a special case that returns a type that matches its parameter - -- (this is without deeper analysis on loaded files and should work most of the time) - local req = typ and typ:match("^require%s*%(?%s*['\"](.+)['\"]%s*%)?") - typ = req or typ - typ = (typ and typ - :gsub("%b()","") - :gsub("%b{}","") - :gsub("%b[]",".0") - -- replace concatenation with addition to avoid misidentifying types - :gsub("%.%.+","+") - -- remove comments; they may be in strings, but that's okay here - :gsub("%-%-.*","")) - if (typ and (typ:match(",") or typ:match("%sor%s") or typ:match("%sand%s"))) then - typ = nil - end - typ = typ and typ:gsub("%s","") - typ = typ and typ:gsub(".+", function(s) - return (s:find("^'[^']*'$") - or s:find('^"[^"]*"$') - or s:find('^%[=*%[.*%]=*%]$')) and 'string' or s - end) - - -- filter out everything that is not needed - if typ and typ ~= 'string' -- special value for all strings - and (not typ:match('^'..identifier..'$') -- not an identifier - or typ:match('^%d') -- or a number - or editor.api.tip.keys[typ] -- or a keyword - ) then - typ = nil - end - - if (var and typ) then - local class,func = typ:match(varname.."["..q(sep).."]"..varname) - if (assigns[typ] and not req) then - assigns[var] = assigns[typ] - elseif (func) then - local added - local funcnames = {"new","load","create"} - for _,v in ipairs(funcnames) do - if (func == v) then - assigns[var] = class - added = true - break - end - end - if (not added) then - -- let's hope autocomplete info can resolve this - assigns[var] = typ - end - else - assigns[var] = typ - end - end - end - line = line+1 - end - - return assigns - end, - - lexerstyleconvert = { - text = {wxstc.wxSTC_LUA_IDENTIFIER,}, - - lexerdef = {wxstc.wxSTC_LUA_DEFAULT,}, - comment = {wxstc.wxSTC_LUA_COMMENT, - wxstc.wxSTC_LUA_COMMENTLINE, - wxstc.wxSTC_LUA_COMMENTDOC,}, - stringtxt = {wxstc.wxSTC_LUA_STRING, - wxstc.wxSTC_LUA_CHARACTER, - wxstc.wxSTC_LUA_LITERALSTRING,}, - stringeol = {wxstc.wxSTC_LUA_STRINGEOL,}, - preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,}, - operator = {wxstc.wxSTC_LUA_OPERATOR,}, - number = {wxstc.wxSTC_LUA_NUMBER,}, - - keywords0 = {wxstc.wxSTC_LUA_WORD,}, - keywords1 = {wxstc.wxSTC_LUA_WORD2,}, - keywords2 = {wxstc.wxSTC_LUA_WORD3,}, - keywords3 = {wxstc.wxSTC_LUA_WORD4,}, - keywords4 = {wxstc.wxSTC_LUA_WORD5,}, - keywords5 = {wxstc.wxSTC_LUA_WORD6,}, - keywords6 = {wxstc.wxSTC_LUA_WORD7,}, - keywords7 = {wxstc.wxSTC_LUA_WORD8,}, - }, - - keywords = { - [[and break do else elseif end for function goto if in local not or repeat return then until while]], - - [[_G _VERSION _ENV false io.stderr io.stdin io.stdout nil math.huge math.pi self true]], - - [[assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring - module next pairs pcall print rawequal rawget rawlen rawset require - select setfenv setmetatable tonumber tostring type unpack xpcall]], - - [[bit32.arshift bit32.band bit32.bnot bit32.bor bit32.btest bit32.bxor bit32.extract - bit32.lrotate bit32.lshift bit32.replace bit32.rrotate bit32.rshift - coroutine.create coroutine.resume coroutine.running coroutine.status coroutine.wrap coroutine.yield - coroutine.isyieldable - debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal - debug.getmetatable debug.getregistry debug.getupvalue debug.getuservalue debug.setfenv - debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.setuservalue - debug.traceback debug.upvalueid debug.upvaluejoin - io.close io.flush io.input io.lines io.open io.output io.popen io.read io.tmpfile io.type io.write - close flush lines read seek setvbuf write - math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.cosh math.deg math.exp - math.floor math.fmod math.frexp math.ldexp math.log math.log10 math.max math.min math.modf - math.pow math.rad math.random math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh - math.type math.tointeger math.maxinteger math.mininteger math.ult - os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename os.setlocale os.time os.tmpname - package.loadlib package.searchpath package.seeall package.config - package.cpath package.loaded package.loaders package.path package.preload package.searchers - string.byte string.char string.dump string.find string.format string.gmatch string.gsub string.len - string.lower string.match string.rep string.reverse string.sub string.upper - byte find format gmatch gsub len lower match rep reverse sub upper - table.move, string.pack, string.unpack, string.packsize - table.concat table.insert table.maxn table.pack table.remove table.sort table.unpack]] - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/text.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/text.lua deleted file mode 100644 index c376542..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/spec/text.lua +++ /dev/null @@ -1,9 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -return { - exts = {"txt"}, - --lexer = wxstc.wxSTC_LEX_POV, - --apitype = "luxres", - linecomment = ">", -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/defs.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/defs.lua deleted file mode 100644 index cce1ffe..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/defs.lua +++ /dev/null @@ -1,332 +0,0 @@ --- About --- ---------------------------------------------------- --- This file contains lua table definitons used by --- automatic loaded files, not part of the --- editor source. --- --- //config.lua --- /cfg/user.lua --- /interpreters/*.lua --- /specs/*.lua --- /tools/*.lua --- /api//*.lua - --- style definition --- ---------------------------------------------------- --- all entries are optional -stattr = { - fg = {r,g,b}, -- foreground color 0-255 - bg = {r,g,b}, -- background color - i = false, -- italic - b = false, -- bold - u = false, -- underline - fill = true, -- fill to lineend - -- fn = "Lucida Console", -- font Face Name - -- fx = 11, -- font size - -- hs = true or {r,g,b}, -- turn hotspot on - -- use the specified color as activeForeground - -- use "hs = true", to turn it on without changing the color - -- HotspotActiveUnderline and HotspotSingleLine are on automatically - -- v = true, -- visibility for symbols of the current style -} - -style = { - -- lexer specific (inherit fg/bg from text) - lexerdef = stattr, - comment = stattr, - stringtxt = stattr, - stringeol = stattr, - preprocessor = stattr, - operator = stattr, - number = stattr, - - keywords0 = stattr, - keywords1 = stattr, - keywords2 = stattr, - keywords3 = stattr, - keywords4 = stattr, - keywords5 = stattr, - keywords6 = stattr, - keywords7 = stattr, - - -- common (inherit fg/bg from text) - text = stattr, - linenumber = stattr, - bracematch = stattr, - bracemiss = stattr, - ctrlchar = stattr, - indent = stattr, - calltip = stattr, - - -- common special (need custom fg & bg ) - sel = nil, - caret = nil, - caretlinebg = nil, - fold = nil, - whitespace = nil, -} - --- config definition --- ---------------------------------------------------- --- tables must exist --- content is optional --- config is loaded into existing config table -config = { - path = { -- path for tools/interpreters - lua = "C:/lua/lua.exe", -- path to lua exe - }, - editor = { - fontname = "Courier New", -- default font - fontsize = 10, -- default size - caretline = true, -- show active line - iofilter = nil, -- input/output filtering of strings - showfncall = true, -- use indicator to show function calls if spec allows - tabwidth = 4, - usetabs = true, -- if false then spaces are used - usewrap = true, -- if true then the text is wrapped in the editor - whitespace = false, - autotabs = true, -- if true test for tabs after file load, - -- sets "usetabs" to true for this file - calltipdelay = nil, -- delay to show calltip (in ms) - autoactivate = false, -- auto-activate/open files during debugging - smartindent = false, -- use smart indentation if spec allows - fold = true, -- enable code folding - foldcompact = true, -- use compact fold that includes empty lines - checkeol = true, -- check for eol encoding on loaded files and use it - -- also report mixed eol encodings - defaulteol = nil, -- default line-endings for new files; valid values are - -- wxstc.wxSTC_EOL_CRLF, wxstc.wxSTC_EOL_LF and nil (OS default) - nomousezoom = nil, -- disable zooming using mouse wheel - autoreload = nil, -- trigger auto-reload when file is updated - saveallonrun = nil, -- save all modified files before Run/Debug - indentguide = true, -- show indentation guides - backspaceunindent = true, -- unindent when backspace is used - }, - - default = { - name = 'untitled', - fullname = 'untitled.lua', - interpreter = 'luadeb', - }, - - debugger = { - verbose = false, - hostname = nil, -- hostname to use when the detected one is incorrect - port = nil, -- port number to use - runonstart = nil, -- if debugger should run immediately after starting - -- default values are different for different interpreters - redirect = nil, -- "d", "c", or "r" values for default, copy, or redirect - }, - - outputshell = { -- output and shell settings - fontname = "Courier New", -- default font - fontsize = 10, -- defult size - }, - - filetree = { -- filetree settings - fontname = nil, -- no default font as it is system dependent - fontsize = nil, -- no default size as it is system dependent - }, - - format = { -- various formatting strings - menurecentprojects = nil, - }, - - keymap = {}, -- mapping of menu IDs to hot keys - messages = {}, -- list of messages in a particular language - language = "en", -- current UI language - - styles = {}, -- styles table as above for editor - stylesoutshell = {}, -- styles for output/shell - - interpreter = "luadeb", -- the default "project" lua interpreter - - autocomplete = true, -- whether autocomplete is on by default - autoanalyzer = true, -- whether auto syntax analyzer is on by default - - acandtip = { - shorttip = false, -- tooltips are compact during typing - nodynwords = false, -- no dynamic words (user entered words) - ignorecase = false, -- ignores case when performing comparison with autocomplete list - symbols = true, -- include local/global symbols - startat = 2, -- start suggesting dynamic words after 2 characters - strategy = 2, - -- 0: is string comparison - -- 1: substring leading characters (camel case or _ separated) - -- 2: leading + any correctly ordered fragments (default) - width = 60, -- width of the tooltip text (in characters) - maxlength = 450, -- max length of the tooltip on the screen - }, - - arg = {}, -- command line arguments - - savebak = false, -- if bak files are created on save - - filehistorylength = 20, -- historylength for files - - projecthistorylength = 15, -- historylength for project directories - - singleinstance = true, -- if true creates a UDP server to run IDE once and to load files - singleinstanceport = 0xe493, -- UDP port for single instance communication - - activateoutput = false, -- activate output/console on Run/Debug/Compile - unhidewindow = false, -- to unhide a gui window - projectautoopen = false, -- allow auto open/close files on a project switch - autorecoverinactivity = nil, -- period of inactivity (s) for autorecover - hidpi = false, -- HiDPI/Retina display support -} - --- application engine --- ---------------------------------------------------- - -app = { - preinit = function() end, -- post spec/tool loading, but prior subsystems/ui generation - postinit = function() end, -- post init, prior starting mainloop - loadfilters = { - tools = function(file) return true end, - specs = function(file) return true end, - interpreters = function(file) return true end, - }, - stringtable = { -- optional entries uses defaults otherwise - editor = nil, statuswelcome = nil, - -- ... - } -} - --- api definition --- ---------------------------------------------------- --- hierarchy encoded into children - -api = { - -- global space words, e.g "table" - ["blah"] = { - -- "function", "class", "keyword", "value", "lib", "method" - -- method is for class:func functions - type = "function", - description = "this does something", - - -- value/function/method: - -- for autocomplete type guessing, insert the string - -- that the variable name is replace with - -- e.g. "test = somefunc()" somefunc has valuetype of "math" - -- then typing "test." will be treated as "math." in - -- autcomplete logic - valuetype = "api.ClassName", - - -- function: - args = "(blah,blubb)", - returns = "(foo)", - - -- autogenerated post load: - -- concated hierarchy name (e.g. "lib.class") - classname = "blah", - - -- children in the class hierarchy - childs = { - --.. recursive - } - }, - ["blubb"] = { - --... - }, -} - --- spec definition --- ---------------------------------------------------- --- all entries are optional -spec = { - exts = {"ext","ext2",}, - -- compatible extensions - - lexer = wxstc.wxSTC_LEX_LUA, - -- scintilla lexer - - lexerstyleconvert = { - -- table mapping each styles to - -- appropriate lexer id - stringeol = {wxstc.wxSTC_LUA_STRINGEOL,}, - -- ... - }, - - linecomment = "//", - -- string for linecomments - - sep = "%.:", - -- class.function separator match string, - -- e.g in lua both . and : are allowed - -- default is "\1" which should yield no matches - -- and therefore disable class.func type autocompletion - - isfncall = function(str) return from,to end, - -- function that detects positions for a substring that - -- stands for a functioncall, ie " call(..)" -> 2,5 - - apitype = "api", - -- which sub directory of "api" is relevant - -- api files handle autocomplete and tooltips - -- api won't affect syntax coloring - - keywords = { - -- up to 8 strings containing space separated keywords - -- used by the lexer for coloring (NOT for autocomplete). - -- however each lexer supports varying amount - -- of keyword types - - "foo bar word", - "more words", - } -} - --- tool definition --- ---------------------------------------------------- --- main entries are optional -tool = { - fninit = function(frame,menubar) end, - -- guarantees that ide is initialized - -- can be used for init - -- and adding custom menu - - exec = { - -- quick exec action, listed under "Tools" menu - name = "", - description = "", - fn = function(wxfilename,projectdir) end, - } -} - --- debuginterface definition --- ---------------------------------------------------- -debuginterface = { - update = function(self) end, -- run in idle when active - close = function(self) end, -- run when closed - - -- following are "debugging" actions and must return - -- error, running, [filePath, fileLine] - run = function(self) end, - step = function(self) end, - over = function(self) end, - out = function(self) end, - terminate = function(self) end, - breaknow = function(self) end, - breakpoint = function(self,file,line,state) end, -- set breakpoint state - - -- returns result table if successful - evaluate = function(self, expressions, fnSetValues) end, -- for watches tables - stack = function(self) end, -- get stack information -} - --- interpreter definition-- ---------------------------------------------------- -interpreter = { - name = "", - description = "", - api = {"apifile_without_extension"}, -- (opt) to limit loaded lua apis - frun = function(self,wfilename,withdebugger) end, - fprojdir = function(self,wfilename) return "projpath_from_filename" end, -- (opt) - fattachdebug = function(self) end, -- (opt) - hasdebugger = false, -- if debugging is available - scratchextloop = nil, -- (opt) indicates scratchpad support - -- nil, no support for scratchpad; - -- false, scratchpad supported; - -- true, scratchpad supported and requires handling for external loop. - skipcompile = nil, -- don't compile before running if true -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/.gui.lua.un~ b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/.gui.lua.un~ deleted file mode 100644 index 756ceb5..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/.gui.lua.un~ and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/autocomplete.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/autocomplete.lua deleted file mode 100644 index f5bd9b9..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/autocomplete.lua +++ /dev/null @@ -1,652 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local q = EscapeMagic - --- api loading depends on Lua interpreter --- and loaded specs - ------------- --- API - -local function newAPI(api) - api = api or {} - for i in pairs(api) do - api[i] = nil - end - -- tool tip info and reserved names - api.tip = { - staticnames = {}, - keys = {}, - finfo = {}, - finfoclass = {}, - shortfinfo = {}, - shortfinfoclass = {}, - } - -- autocomplete hierarchy - api.ac = { - childs = {}, - } - - return api -end - -local apis = { - none = newAPI(), - lua = newAPI(), -} - -function GetApi(apitype) return apis[apitype] or apis.none end - ----------- --- API loading - -local function gennames(tab, prefix) - for i,v in pairs(tab) do - v.classname = (prefix and (prefix..".") or "")..i - if (v.childs) then - gennames(v.childs,v.classname) - end - end -end - -local function addAPI(ftype, fname) -- relative to API directory - local env = apis[ftype] or newAPI() - - local res - local api = ide.apis[ftype][fname] - - if type(api) == 'table' then - res = api - else - local fn, err = loadfile(api) - if err then - DisplayOutputLn(TR("Error while loading API file: %s"):format(err)) - return - end - local suc - suc, res = pcall(function() return fn(env.ac.childs) end) - if (not suc) then - DisplayOutputLn(TR("Error while processing API file: %s"):format(res)) - return - end - -- cache the result - ide.apis[ftype][fname] = res - end - apis[ftype] = env - - gennames(res) - for i,v in pairs(res) do env.ac.childs[i] = v end -end - -local function loadallAPIs(only, subapis, known) - for ftype, v in pairs(only and {[only] = ide.apis[only]} or ide.apis) do - if (not known or known[ftype]) then - for fname in pairs(v) do - if (not subapis or subapis[fname]) then addAPI(ftype, fname) end - end - end - end -end - -local function scanAPIs() - for _, file in ipairs(FileSysGetRecursive("api", true, "*.lua")) do - if not IsDirectory(file) then - local ftype, fname = file:match("api[/\\]([^/\\]+)[/\\](.*)%.") - if not ftype or not fname then - DisplayOutputLn(TR("The API file must be located in a subdirectory of the API directory.")) - return - end - ide.apis[ftype] = ide.apis[ftype] or {} - ide.apis[ftype][fname] = file - end - end -end - ---------- --- ToolTip and reserved words list --- also fixes function descriptions - -local function fillTips(api,apibasename) - local apiac = api.ac - local tclass = api.tip - - tclass.staticnames = {} - tclass.keys = {} - tclass.finfo = {} - tclass.finfoclass = {} - tclass.shortfinfo = {} - tclass.shortfinfoclass = {} - - local staticnames = tclass.staticnames - local keys = tclass.keys - local finfo = tclass.finfo - local finfoclass = tclass.finfoclass - local shortfinfo = tclass.shortfinfo - local shortfinfoclass = tclass.shortfinfoclass - - local function traverse (tab, libname, format) - if not tab.childs then return end - format = tab.format or format - for key,info in pairs(tab.childs) do - local fullkey = (libname ~= "" and libname.."." or "")..key - traverse(info, fullkey, format) - - if info.type == "function" or info.type == "method" or info.type == "value" then - local frontname = (info.returns or "(?)").." "..fullkey.." "..(info.args or "(?)") - frontname = frontname:gsub("\n"," "):gsub("\t","") - local description = info.description or "" - - -- build info - local inf = ((info.type == "value" and "" or frontname.."\n") - ..description) - local sentence = description:match("^(.-)%. ?\n") - local infshort = ((info.type == "value" and "" or frontname.."\n") - ..(sentence and sentence.."..." or description)) - if type(format) == 'function' then -- apply custom formatting if requested - inf = format(fullkey, info, inf) - infshort = format(fullkey, info, infshort) - end - local infshortbatch = (info.returns and info.args) and frontname or infshort - - -- add to infoclass - if not finfoclass[libname] then finfoclass[libname] = {} end - if not shortfinfoclass[libname] then shortfinfoclass[libname] = {} end - finfoclass[libname][key] = inf - shortfinfoclass[libname][key] = infshort - - -- add to info - if not finfo[key] or #finfo[key]<200 then - if finfo[key] then finfo[key] = finfo[key] .. "\n\n" - else finfo[key] = "" end - finfo[key] = finfo[key] .. inf - elseif not finfo[key]:match("\n %(%.%.%.%)$") then - finfo[key] = finfo[key].."\n (...)" - end - - -- add to shortinfo - if not shortfinfo[key] or #shortfinfo[key]<200 then - if shortfinfo[key] then shortfinfo[key] = shortfinfo[key] .. "\n" - else shortfinfo[key] = "" end - shortfinfo[key] = shortfinfo[key] .. infshortbatch - elseif not shortfinfo[key]:match("\n %(%.%.%.%)$") then - shortfinfo[key] = shortfinfo[key].."\n (...)" - end - end - if info.type == "keyword" then - keys[key] = true - end - staticnames[key] = true - end - end - traverse(apiac,apibasename) -end - -local function generateAPIInfo(only) - for i,api in pairs(apis) do - if ((not only) or i == only) then - fillTips(api,"") - end - end -end - -local function updateAssignCache(editor) - if (editor.spec.typeassigns and not editor.assignscache) then - local assigns = editor.spec.typeassigns(editor) - editor.assignscache = { - assigns = assigns, - line = editor:GetCurrentLine(), - } - end -end - --- assumes a tidied up string (no spaces, braces..) -local function resolveAssign(editor,tx) - local ac = editor.api.ac - local sep = editor.spec.sep - local anysep = "["..q(sep).."]" - local assigns = editor.assignscache and editor.assignscache.assigns - local function getclass(tab,a) - local key,rest = a:match("([%w_]+)"..anysep.."(.*)") - key = tonumber(key) or key -- make this work for childs[0] - if (key and rest and tab.childs and tab.childs[key]) then - return getclass(tab.childs[key],rest) - end - -- process valuetype, but only if it doesn't reference the current tab - if (tab.valuetype and tab ~= ac.childs[tab.valuetype]) then - return getclass(ac,tab.valuetype..sep:sub(1,1)..a) - end - return tab,a - end - - local c - if (assigns) then - -- find assign - local change, n, refs, stopat = true, 0, {}, os.clock() + 0.2 - while (change) do - -- abort the check if the auto-complete is taking too long - if n > 50 and os.clock() > stopat then - if ide.config.acandtip.warning then - DisplayOutputLn("Warning: Auto-complete was aborted after taking too long to complete." - .. " Please report this warning along with the text you were typing to support@zerobrane.com.") - end - break - else - n = n + 1 - end - - local classname = nil - c = "" - change = false - for w,s in tx:gmatch("([%w_]+)("..anysep.."?)") do - local old = classname - -- check if what we have so far can be matched with a class name - -- this can happen if it's a reference to a value with a known type - classname = classname or assigns[c..w] - if (s ~= "" and old ~= classname) then - -- continue checking unless this can lead to recursive substitution - change = not classname:find("^"..w) and not classname:find("^"..c..w) - c = classname..s - else - c = c..w..s - end - end - -- check for loops in type assignment - if refs[tx] then break end - refs[tx] = c - tx = c - -- if there is any class duplication, abort the loop - if classname and select(2, c:gsub(classname, classname)) > 1 then break end - end - else - c = tx - end - - -- then work from api - return getclass(ac,c) -end - -function GetTipInfo(editor, content, short, fullmatch) - if not content then return end - - updateAssignCache(editor) - - -- try to resolve the class - content = content:gsub("%b[]",".0") - local tab = resolveAssign(editor, content) - local sep = editor.spec.sep - local anysep = "["..q(sep).."]" - - local caller = content:match("([%w_]+)%(?%s*$") - local class = (tab and tab.classname - or caller and content:match("([%w_]+)"..anysep..caller.."%(?%s*$") or "") - local tip = editor.api.tip - - local classtab = short and tip.shortfinfoclass or tip.finfoclass - local funcstab = short and tip.shortfinfo or tip.finfo - - if (editor.assignscache and not (class and classtab[class])) then - local assigns = editor.assignscache.assigns - class = assigns and assigns[class] or class - end - - local res = (caller and (class and classtab[class]) and classtab[class][caller] - or (not fullmatch and funcstab[caller] or nil)) - -- some values may not have descriptions (for example, true/false); - -- don't return empty strings as they are displayed as empty tooltips. - return res and #res > 0 and res or nil -end - -local function reloadAPI(only,subapis) - newAPI(apis[only]) - loadallAPIs(only,subapis) - generateAPIInfo(only) -end - -function ReloadLuaAPI() - local interp = ide.interpreter - local cfgapi = ide.config.api - local fname = interp and interp.fname - local intapi = cfgapi and fname and cfgapi[fname] - local apinames = {} - -- general APIs as configured - for _, v in ipairs(type(cfgapi) == 'table' and cfgapi or {}) do apinames[v] = true end - -- interpreter-specific APIs as configured - for _, v in ipairs(type(intapi) == 'table' and intapi or {}) do apinames[v] = true end - -- interpreter APIs - for _, v in ipairs(interp and interp.api or {}) do apinames[v] = true end - reloadAPI("lua",apinames) -end - -do - local known = {} - for _, spec in pairs(ide.specs) do - if (spec.apitype) then - known[spec.apitype] = true - end - end - -- by defaul load every known api except lua - known.lua = false - - scanAPIs() - loadallAPIs(nil,nil,known) - generateAPIInfo() -end - -------------- --- Dynamic Words - -local dywordentries = {} -local dynamicwords = {} - -local function addDynamicWord (api,word) - if api.tip.keys[word] or api.tip.staticnames[word] then return end - local cnt = dywordentries[word] - if cnt then - dywordentries[word] = cnt + 1 - return - end - dywordentries[word] = 1 - local wlow = word:lower() - for i=0,#word do - local k = wlow:sub(1,i) - dynamicwords[k] = dynamicwords[k] or {} - table.insert(dynamicwords[k], word) - end -end -local function removeDynamicWord (api,word) - if api.tip.keys[word] or api.tip.staticnames[word] then return end - local cnt = dywordentries[word] - if not cnt then return end - - if (cnt == 1) then - dywordentries[word] = nil - for i=0,#word do - local wlow = word:lower() - local k = wlow : sub (1,i) - local page = dynamicwords[k] - if page then - local cnt = #page - for n=1,cnt do - if page[n] == word then - if cnt == 1 then - dynamicwords[k] = nil - else - table.remove(page,n) - end - break - end - end - end - end - else - dywordentries[word] = cnt - 1 - end -end -function DynamicWordsReset () - dywordentries = {} - dynamicwords = {} -end - -local function getEditorLines(editor,line,numlines) - return editor:GetTextRangeDyn( - editor:PositionFromLine(line),editor:PositionFromLine(line+numlines+1)) -end - -function DynamicWordsAdd(editor,content,line,numlines) - if ide.config.acandtip.nodynwords then return end - local api = editor.api - local anysep = "["..q(editor.spec.sep).."]" - content = content or getEditorLines(editor,line,numlines) - for word in content:gmatch(anysep.."?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)") do - addDynamicWord(api,word) - end -end - -function DynamicWordsRem(editor,content,line,numlines) - if ide.config.acandtip.nodynwords then return end - local api = editor.api - local anysep = "["..q(editor.spec.sep).."]" - content = content or getEditorLines(editor,line,numlines) - for word in content:gmatch(anysep.."?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)") do - removeDynamicWord(api,word) - end -end - -function DynamicWordsRemoveAll(editor) - if ide.config.acandtip.nodynwords then return end - DynamicWordsRem(editor,editor:GetTextDyn()) -end - ------------- --- Final Autocomplete - -local cachemain = {} -local cachemethod = {} -local laststrategy -local function getAutoCompApiList(childs,fragment,method) - fragment = fragment:lower() - local strategy = ide.config.acandtip.strategy - if (laststrategy ~= strategy) then - cachemain = {} - cachemethod = {} - laststrategy = strategy - end - - local cache = method and cachemethod or cachemain - - if (strategy == 2) then - local wlist = cache[childs] - if not wlist then - wlist = " " - for i,v in pairs(childs) do - -- in some cases (tip.finfo), v may be a string; check for that first. - -- if a:b typed, then value (type == "value") not allowed - -- if a.b typed, then method (type == "method") not allowed - if type(v) ~= 'table' or (v.type and - ((method and v.type ~= "value") - or (not method and v.type ~= "method"))) then - wlist = wlist..i.." " - end - end - cache[childs] = wlist - end - local ret = {} - local g = string.gmatch - local pat = fragment ~= "" and ("%s("..fragment:gsub(".", - function(c) - local l = c:lower()..c:upper() - return "["..l.."][%w_]*" - end)..")") or "([%w_]+)" - pat = pat:gsub("%s","") - for c in g(wlist,pat) do - table.insert(ret,c) - end - - return ret - end - - if cache[childs] and cache[childs][fragment] then - return cache[childs][fragment] - end - - local t = {} - cache[childs] = t - - local sub = strategy == 1 - for key,v in pairs(childs) do - -- in some cases (tip.finfo), v may be a string; check for that first. - -- if a:b typed, then value (type == "value") not allowed - -- if a.b typed, then method (type == "method") not allowed - if type(v) ~= 'table' or (v.type and - ((method and v.type ~= "value") - or (not method and v.type ~= "method"))) then - local used = {} - local kl = key:lower() - for i=0,#key do - local k = kl:sub(1,i) - t[k] = t[k] or {} - used[k] = true - table.insert(t[k],key) - end - if (sub) then - -- find camel case / _ separated subwords - -- glfwGetGammaRamp -> g, gg, ggr - -- GL_POINT_SPRIT -> g, gp, gps - local last = "" - for ks in string.gmatch(key,"([A-Z%d]*[a-z%d]*_?)") do - local k = last..(ks:sub(1,1):lower()) - last = k - - t[k] = t[k] or {} - if (not used[k]) then - used[k] = true - table.insert(t[k],key) - end - end - end - end - end - - return t -end - -function CreateAutoCompList(editor,key,pos) - local api = editor.api - local tip = api.tip - local ac = api.ac - local sep = editor.spec.sep - - local method = key:match(":[^"..q(sep).."]*$") ~= nil - - -- ignore keywords - if tip.keys[key] then return end - - updateAssignCache(editor) - - local tab,rest = resolveAssign(editor,key) - local progress = tab and tab.childs - ide:SetStatusFor(progress and tab.classname and ("Auto-completing '%s'..."):format(tab.classname) or "") - if not progress then return end - - if (tab == ac) then - local _, krest = rest:match("([%w_]+)["..q(sep).."]([%w_]*)%s*$") - if (krest) then - tab = #krest >= (ide.config.acandtip.startat or 2) and tip.finfo or {} - rest = krest:gsub("[^%w_]","") - else - rest = rest:gsub("[^%w_]","") - end - else - rest = rest:gsub("[^%w_]","") - end - - -- list from api - local apilist = getAutoCompApiList(tab.childs or tab,rest,method) - - local function addInheritance(tab, apilist, seen) - if not tab.inherits then return end - for base in tab.inherits:gmatch("[%w_"..q(sep).."]+") do - local tab = ac - -- map "a.b.c" to class hierarchy (a.b.c) - for class in base:gmatch("[%w_]+") do tab = tab.childs[class] end - - if tab and not seen[tab] then - seen[tab] = true - for _,v in pairs(getAutoCompApiList(tab.childs,rest,method)) do - table.insert(apilist, v) - end - addInheritance(tab, apilist, seen) - end - end - end - - -- handle (multiple) inheritance; add matches from the parent class/lib - addInheritance(tab, apilist, {[tab] = true}) - - -- include local/global variables - if ide.config.acandtip.symbols and not key:find(q(sep)) then - local vars, context = {} - local tokens = editor:GetTokenList() - for _, token in ipairs(tokens) do - if token.fpos and pos and token.fpos > pos then break end - if token[1] == 'Id' or token[1] == 'Var' then - local var = token.name - if var:find(key, 1, true) == 1 - -- skip the variable formed by what's being typed - and (not token.fpos or not pos or token.fpos < pos-#key) then - -- if it's a global variable, store in the auto-complete list, - -- but if it's local, store separately as it needs to be checked - table.insert(token.context[var] and vars or apilist, var) - end - context = token.context - end - end - for _, var in pairs(context and vars or {}) do - if context[var] then table.insert(apilist, var) end - end - end - - -- include dynamic words - local last = key:match("([%w_]+)%s*$") - if (last and #last >= (ide.config.acandtip.startat or 2)) then - last = last:lower() - for i,v in ipairs(dynamicwords[last] or {}) do - -- ignore if word == last and sole user - if (v:lower() == last and dywordentries[v] == 1) then break end - table.insert(apilist, v) - end - end - - local li - if apilist then - if (#rest > 0) then - local strategy = ide.config.acandtip.strategy - - if (strategy == 2 and #apilist < 128) then - -- when matching "ret": "ret." < "re.t" < "r.et" - local patany = rest:gsub(".", function(c) return "["..c:lower()..c:upper().."](.-)" end) - local patcase = rest:gsub(".", function(c) return c.."(.-)" end) - local weights = {} - local penalty = 0.1 - local function weight(str) - if not weights[str] then - local w = 0 - str:gsub(patany,function(...) - local l = {...} - -- penalize gaps between matches, more so at the beginning - for n, v in ipairs(l) do w = w + #v * (1 + (#l-n)*penalty) end - end) - weights[str] = w + (str:find(patcase) and 0 or penalty) - end - return weights[str] - end - table.sort(apilist,function(a,b) - local ma, mb = weight(a), weight(b) - if (ma == mb) then return a:lower() 1024 and li:sub(1,1024).."..." or li -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commandbar.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commandbar.lua deleted file mode 100644 index 26de6fd..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commandbar.lua +++ /dev/null @@ -1,359 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC ---------------------------------------------------------- - -local unpack = table.unpack or unpack -local maxlines = 8 -local row_height = 46 - -function CommandBarShow(params) - local onDone, onUpdate, onItem, onSelection, defaultText, selectedText = - params.onDone, params.onUpdate, params.onItem, params.onSelection, - params.defaultText, params.selectedText - local row_width = ide.config.commandbar.width or 0 - if row_width < 1 then - row_width = math.max(450, math.floor(row_width * ide:GetMainFrame():GetClientSize():GetWidth())) - end - - local lines = {} - local linesnow = #lines - local linenow = 0 - - local nb = ide:GetEditorNotebook() - local pos = nb:GetScreenPosition() - if pos then - local miny - for p = 0, nb:GetPageCount()-1 do - local y = nb:GetPage(p):GetScreenPosition():GetY() - -- just in case, compare with the position of the notebook itself; - -- this is needed because the tabs that haven't been refreshed yet - -- may report 0 as their screen position on Linux, which is incorrect. - if y > pos:GetY() and (not miny or y < miny) then miny = y end - end - pos:SetX(pos:GetX()+nb:GetClientSize():GetWidth()-row_width-16) - pos:SetY((miny or pos:GetY())+2) - else - pos = wx.wxDefaultPosition - end - - local frame = wx.wxFrame(ide:GetMainFrame(), wx.wxID_ANY, "Command Bar", - pos, wx.wxDefaultSize, - wx.wxFRAME_NO_TASKBAR + wx.wxFRAME_FLOAT_ON_PARENT + wx.wxNO_BORDER) - local panel = wx.wxPanel(frame or ide:GetMainFrame(), wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxFULL_REPAINT_ON_RESIZE) - local search = wx.wxTextCtrl(panel, wx.wxID_ANY, "\1", - wx.wxDefaultPosition, - -- make the text control a bit smaller on OSX - wx.wxSize(row_width, ide.osname == 'Macintosh' and 20 or 24), - wx.wxTE_PROCESS_ENTER + wx.wxTE_PROCESS_TAB + wx.wxNO_BORDER) - local results = wx.wxScrolledWindow(panel, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(0, 0)) - - local style, styledef = ide.config.styles, StylesGetDefault() - local textcolor = wx.wxColour(unpack(style.text.fg or styledef.text.fg)) - local backcolor = wx.wxColour(unpack(style.text.bg or styledef.text.bg)) - local selcolor = wx.wxColour(unpack(style.caretlinebg.bg or styledef.caretlinebg.bg)) - local pancolor = ide:GetUIManager():GetArtProvider():GetColor(wxaui.wxAUI_DOCKART_SASH_COLOUR) - local borcolor = ide:GetUIManager():GetArtProvider():GetColor(wxaui.wxAUI_DOCKART_BORDER_COLOUR) - - search:SetBackgroundColour(backcolor) - search:SetForegroundColour(textcolor) - - local nbrush = wx.wxBrush(backcolor, wx.wxSOLID) - local sbrush = wx.wxBrush(selcolor, wx.wxSOLID) - local bbrush = wx.wxBrush(pancolor, wx.wxSOLID) - local lpen = wx.wxPen(borcolor, 1, wx.wxDOT) - local bpen = wx.wxPen(borcolor, 1, wx.wxSOLID) - - local sash = ide:GetUIManager():GetArtProvider():GetMetric(wxaui.wxAUI_DOCKART_SASH_SIZE) - local border = sash + 2 - local hoffset = 4 - local voffset = 4 - - local topSizer = wx.wxFlexGridSizer(2, 1, -border*2, 0) - topSizer:SetFlexibleDirection(wx.wxVERTICAL) - topSizer:AddGrowableRow(1, 1) - topSizer:Add(search, wx.wxSizerFlags(0):Expand():Border(wx.wxALL, border)) - topSizer:Add(results, wx.wxSizerFlags(1):Expand():Border(wx.wxALL, border)) - panel:SetSizer(topSizer) - topSizer:Fit(frame) -- fit the frame/panel around the controls - - local minheight = frame:GetClientSize():GetHeight() - - local tfont = ide:GetProjectTree():GetFont() - local ffont = (ide:GetEditor() or ide:CreateBareEditor()):GetFont() - ffont:SetPointSize(ffont:GetPointSize()+2) - local sfont = wx.wxFont(tfont) - tfont:SetPointSize(tfont:GetPointSize()+2) - search:SetFont(tfont) - - -- make a one-time callback; - -- needed because KILL_FOCUS handler can be called after closing window - local function onExit(index) - onExit = function() end - onDone(index and lines[index], index, search:GetValue()) - frame:Close() - end - - local function onPaint(event) - -- adjust the scrollbar before working with the canvas - local _, starty = results:GetViewStart() - if #lines ~= linesnow then - -- adjust the starting line when the current line is the last one - if linenow > starty+maxlines then starty = starty + 1 end - results:SetScrollbars(1, row_height, 1, #lines, 0, starty*row_height, false) - linesnow = #lines - end - - local dc = wx.wxMemoryDC(results) - results:PrepareDC(dc) - - local size = results:GetVirtualSize() - local w,h = size:GetWidth(),size:GetHeight() - local bitmap = wx.wxBitmap(w,h) - dc:SelectObject(bitmap) - - -- clear the background - dc:SetBackground(nbrush) - dc:Clear() - - dc:SetTextForeground(textcolor) - dc:SetBrush(sbrush) - for r = 1, #lines do - if r == linenow then - dc:SetPen(wx.wxTRANSPARENT_PEN) - dc:DrawRectangle(0, row_height*(r-1), row_width, row_height+1) - end - dc:SetPen(lpen) - dc:DrawLine(hoffset, row_height*(r-1), row_width-hoffset*2, row_height*(r-1)) - - local fline, sline = onItem(lines[r]) - if fline then - dc:SetFont(ffont) - dc:DrawText(fline, hoffset, row_height*(r-1)+voffset) - end - if sline then - dc:SetFont(sfont) - dc:DrawText(sline, hoffset, row_height*(r-1)+row_height/2+voffset) - end - end - - dc:SetPen(wx.wxNullPen) - dc:SetBrush(wx.wxNullBrush) - dc:SelectObject(wx.wxNullBitmap) - dc:delete() - - dc = wx.wxPaintDC(results) - dc:DrawBitmap(bitmap, 0, 0, true) - dc:delete() - end - - local function onPanelPaint(event) - local dc = wx.wxBufferedPaintDC(panel) - dc:SetBrush(bbrush) - dc:SetPen(bpen) - - local psize = panel:GetClientSize() - dc:DrawRectangle(0, 0, psize:GetWidth(), psize:GetHeight()) - dc:DrawRectangle(sash+1, sash+1, psize:GetWidth()-2*(sash+1), psize:GetHeight()-2*(sash+1)) - - dc:SetPen(wx.wxNullPen) - dc:SetBrush(wx.wxNullBrush) - dc:delete() - end - - local linewas -- line that was reported when updated - local function onTextUpdated(event) - local text = search:GetValue() - lines = onUpdate(text) - linenow = #text > 0 and #lines > 0 and 1 or 0 - linewas = nil - - local size = frame:GetClientSize() - local height = minheight + row_height*math.min(maxlines,#lines) - if height ~= size:GetHeight() then - results:SetScrollbars(1, 1, 1, 1, 0, 0, false) - size:SetHeight(height) - frame:SetClientSize(size) - end - - results:Refresh() - end - - local function onKeyDown(event) - local keycode = event:GetKeyCode() - if keycode == wx.WXK_RETURN then - onExit(linenow) - return - elseif event:GetModifiers() ~= wx.wxMOD_NONE then - event:Skip() - return - elseif keycode == wx.WXK_UP then - if linesnow > 0 then - linenow = linenow - 1 - if linenow <= 0 then linenow = linesnow end - end - elseif keycode == wx.WXK_DOWN then - if linesnow > 0 then - linenow = linenow % linesnow + 1 - end - elseif keycode == wx.WXK_PAGEDOWN then - if linesnow > 0 then - linenow = linenow + maxlines - if linenow > linesnow then linenow = linesnow end - end - elseif keycode == wx.WXK_PAGEUP then - if linesnow > 0 then - linenow = linenow - maxlines - if linenow <= 0 then linenow = 1 end - end - elseif keycode == wx.WXK_ESCAPE then - onExit(false) - return - else - event:Skip() - return - end - - local _, starty = results:GetViewStart() - if linenow < starty+1 then results:Scroll(-1, linenow-1) - elseif linenow > starty+maxlines then results:Scroll(-1, linenow-maxlines) end - results:Refresh() - end - - local function onMouseLeftDown(event) - local pos = event:GetPosition() - local _, y = results:CalcUnscrolledPosition(pos.x, pos.y) - onExit(math.floor(y / row_height)+1) - end - - local function onIdle(event) - if linewas == linenow then return end - linewas = linenow - if linenow == 0 then return end - - -- save the selection/insertion point as it's reset on Linux (wxwidgets 2.9.5) - local ip = search:GetInsertionPoint() - local f, t = search:GetSelection() - - -- this may set focus to a different object/tab, - -- so disable the focus event and then set the focus back - search:SetEvtHandlerEnabled(false) - onSelection(lines[linenow], search:GetValue()) - search:SetFocus() - search:SetEvtHandlerEnabled(true) - if ide.osname == 'Unix' then - search:SetInsertionPoint(ip) - search:SetSelection(f, t) - end - end - - frame:Connect(wx.wxEVT_CLOSE_WINDOW, function() frame:Destroy() end) - - panel:Connect(wx.wxEVT_PAINT, onPanelPaint) - panel:Connect(wx.wxEVT_ERASE_BACKGROUND, function() end) - panel:Connect(wx.wxEVT_IDLE, onIdle) - - results:Connect(wx.wxEVT_PAINT, onPaint) - results:Connect(wx.wxEVT_LEFT_DOWN, onMouseLeftDown) - results:Connect(wx.wxEVT_ERASE_BACKGROUND, function() end) - - search:SetFocus() - search:Connect(wx.wxEVT_KEY_DOWN, onKeyDown) - search:Connect(wx.wxEVT_COMMAND_TEXT_UPDATED, onTextUpdated) - search:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, function() onExit(linenow) end) - search:Connect(wx.wxEVT_KILL_FOCUS, function() onExit() end) - - frame:Show(true) - frame:Update() - frame:Refresh() - - search:SetValue((defaultText or "")..(selectedText or "")) - search:SetSelection(#(defaultText or ""), -1) -end - -local sep = "[/\\%-_ ]+" -local weights = {onegram = 0.1, digram = 0.4, trigram = 0.5} -local cache = {} -local missing = 3 -- penalty for missing symbols (1 missing == N matching) -local casemismatch = 0.9 -- score for case mismatch (%% of full match) -local function score(p, v) - local function ngrams(str, num, low, needcache) - local key = str..'\1'..num - if cache[key] then return unpack(cache[key]) end - - local t, l, p = {}, {}, 0 - for i = 1, #str-num+1 do - local pair = str:sub(i, i+num-1) - p = p + (t[pair] and 0 or 1) - if low and pair:find('%u') then l[pair:lower()] = casemismatch end - t[pair] = 1 - end - if needcache then cache[key] = {t, p, l} end - return t, p, l - end - - local function overlap(pattern, value, num) - local ph, ps = ngrams(pattern, num, false, true) - local vh, vs, vl = ngrams(value, num, true) - if ps + vs == 0 then return 0 end - - local is = 0 -- intersection of two sets of ngrams - for k in pairs(ph) do is = is + (vh[k] or vl[k:lower()] or 0) end - return is / (ps + vs) - (num == 1 and missing * (ps - is) / (ps + vs) or 0) - end - - local key = p..'\2'..v - if not cache[key] then - local score = weights.onegram * overlap(p, v, 1) - if score > 0 then -- don't bother with those that can't even score 1grams - p = ' '..(p:gsub(sep, ' ')) - v = ' '..(v:gsub(sep, ' ')) - score = score + weights.digram * overlap(p, v, 2) - score = score + weights.trigram * overlap(' '..p, ' '..v, 3) - end - cache[key] = 2 * 100 * score - end - return cache[key] -end - -function CommandBarScoreItems(t, pattern, limit) - local r, plen = {}, #pattern - local maxp = 0 - local num = 0 - local prefilter = ide.config.commandbar and ide.config.commandbar.prefilter - -- anchor for 1-2 symbol patterns to speed up search - local needanchor = prefilter and prefilter * 4 <= #t and plen <= 2 - local filter = prefilter and prefilter <= #t - -- expand `abc` into `a.*b.*c`, but limit the prefix to avoid penalty for `s.*s.*s.*....` - and pattern:gsub("[^%w_]+",""):sub(1,4):lower():gsub(".", "%1.*"):gsub("%.%*$","") - or nil - for _, v in ipairs(t) do - if #v >= plen then - local match = filter and v:lower():find(filter) - -- check if the current name needs to be prefiltered or anchored (for better performance); - -- if it needs to be anchored, then anchor it at the beginning of the string or the word - if not filter or (match and (not needanchor or match == 1 or v:find("^[%p%s]", match-1))) then - local p = score(pattern, v) - maxp = math.max(p, maxp) - if p > 1 and p > maxp / 4 then - num = num + 1 - r[num] = {v, p} - end - end - end - end - table.sort(r, function(a, b) return a[2] > b[2] end) - -- limit the list to be displayed - -- `r[limit+1] = nil` is not desired as the resulting table may be sorted incorrectly - if tonumber(limit) and limit < #r then - local tmp = r - r = {} - for i = 1, limit do r[i] = tmp[i] end - end - return r -end - -ide:AddPackage('core.commandbar', { - -- reset ngram cache when switching projects to conserve memory - onProjectLoad = function() cache = {} end - }) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commands.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commands.lua deleted file mode 100644 index 8695659..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/commands.lua +++ /dev/null @@ -1,1054 +0,0 @@ --- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local notebook = frame.notebook -local openDocuments = ide.openDocuments -local uimgr = frame.uimgr -local unpack = table.unpack or unpack - -local CURRENT_LINE_MARKER = StylesGetMarker("currentline") -local CURRENT_LINE_MARKER_VALUE = 2^CURRENT_LINE_MARKER - -function NewFile(filename) - filename = filename or ide.config.default.fullname - local editor = CreateEditor() - editor:SetupKeywords(GetFileExt(filename)) - local doc = AddEditor(editor, filename) - if doc then - PackageEventHandle("onEditorNew", editor) - SetEditorSelection(doc.index) - end - return editor -end - --- Find an editor page that hasn't been used at all, eg. an untouched NewFile() -local function findUnusedEditor() - local editor - for _, document in pairs(openDocuments) do - if (document.editor:GetLength() == 0) and - (not document.isModified) and (not document.filePath) and - not (document.editor:GetReadOnly() == true) then - editor = document.editor - break - end - end - return editor -end - -function LoadFile(filePath, editor, file_must_exist, skipselection) - filePath = filePath:gsub("%s+$","") - filePath = wx.wxFileName(filePath) - filePath:Normalize() -- make it absolute and remove all .. and . if possible - filePath = filePath:GetFullPath() - - -- if the file name is empty or is a directory, don't do anything - if filePath == '' or wx.wxDirExists(filePath) then return nil end - - -- prevent files from being reopened again - if (not editor) then - local doc = ide:FindDocument(filePath) - if doc then - if not skipselection and doc.index ~= notebook:GetSelection() then - -- selecting the same tab doesn't trigger PAGE_CHANGE event, - -- but moves the focus to the tab bar, which needs to be avoided. - notebook:SetSelection(doc.index) - end - return doc.editor - end - end - - local filesize = FileSize(filePath) - if not filesize and file_must_exist then return nil end - - local current = editor and editor:GetCurrentPos() - editor = editor or findUnusedEditor() or CreateEditor() - editor:Freeze() - editor:SetupKeywords(GetFileExt(filePath)) - editor:MarkerDeleteAll(-1) - if filesize then editor:Allocate(filesize) end - editor:SetTextDyn("") - editor.bom = string.char(0xEF,0xBB,0xBF) - - local inputfilter = GetConfigIOFilter("input") - local file_text - ide:PushStatus("") - FileRead(filePath, 1024*1024, function(s) - if not file_text then - -- remove BOM from UTF-8 encoded files; store BOM to add back when saving - if s and editor:GetCodePage() == wxstc.wxSTC_CP_UTF8 and s:find("^"..editor.bom) then - s = s:gsub("^"..editor.bom, "") - else - -- set to 'false' as checks for nil on wxlua objects may fail at run-time - editor.bom = false - end - file_text = s - end - if inputfilter then s = inputfilter(filePath, s) end - local expected = editor:GetLength() + #s - editor:AppendTextDyn(s) - -- if the length is not as expected, then either it's a binary file or invalid UTF8 - if editor:GetLength() ~= expected then - -- skip binary files with unknown extensions as they may have any sequences - -- when using Raw methods, this can only happen for binary files (that include \0 chars) - if editor.useraw or editor.spec == ide.specs.none and IsBinary(s) then - DisplayOutputLn(("%s: %s"):format(filePath, - TR("Binary file is shown as read-only as it is only partially loaded."))) - file_text = '' - editor:SetReadOnly(true) - return false - end - - -- handle invalid UTF8 characters - -- fix: doesn't handle characters split by callback buffer - local replacement, invalid = "\022" - s, invalid = FixUTF8(s, replacement) - if #invalid > 0 then - editor:AppendTextDyn(s) - local lastline = nil - for _, n in ipairs(invalid) do - local line = editor:LineFromPosition(n) - if line ~= lastline then - DisplayOutputLn(("%s:%d: %s"):format(filePath, line+1, - TR("Replaced an invalid UTF8 character with %s."):format(replacement))) - lastline = line - end - end - end - end - if filesize and filesize > 0 then - ide:PopStatus() - ide:PushStatus(TR("%s%% loaded..."):format(math.floor(100*editor:GetLength()/filesize))) - end - end) - ide:PopStatus() - - editor:Colourise(0, -1) - editor:ResetTokenList() -- reset list of tokens if this is a reused editor - editor:Thaw() - - local edcfg = ide.config.editor - if current then editor:GotoPos(current) end - if (file_text and edcfg.autotabs) then - -- use tabs if they are already used - -- or if "usetabs" is set and no space indentation is used in a file - editor:SetUseTabs(string.find(file_text, "\t") ~= nil - or edcfg.usetabs and (file_text:find("%f[^\r\n] ") or file_text:find("^ ")) == nil) - end - - if (file_text and edcfg.checkeol) then - -- Auto-detect CRLF/LF line-endings - local foundcrlf = string.find(file_text,"\r\n") ~= nil - local foundlf = (string.find(file_text,"[^\r]\n") ~= nil) - or (string.find(file_text,"^\n") ~= nil) -- edge case: file beginning with LF and having no other LF - if foundcrlf and foundlf then -- file with mixed line-endings - DisplayOutputLn(("%s: %s") - :format(filePath, TR("Mixed end-of-line encodings detected.")..' '.. - TR("Use '%s' to show line endings and '%s' to convert them.") - :format("ide:GetEditor():SetViewEOL(1)", "ide:GetEditor():ConvertEOLs(ide:GetEditor():GetEOLMode())"))) - elseif foundcrlf then - editor:SetEOLMode(wxstc.wxSTC_EOL_CRLF) - elseif foundlf then - editor:SetEOLMode(wxstc.wxSTC_EOL_LF) - -- else (e.g. file is 1 line long or uses another line-ending): use default EOL mode - end - end - - editor:EmptyUndoBuffer() - local doc = ide:GetDocument(editor) - if doc then -- existing editor; switch to the tab - notebook:SetSelection(doc:GetTabIndex()) - else -- the editor has not been added to notebook - doc = AddEditor(editor, wx.wxFileName(filePath):GetFullName() - or ide.config.default.fullname) - end - doc.filePath = filePath - doc.fileName = wx.wxFileName(filePath):GetFullName() - doc.modTime = GetFileModTime(filePath) - - doc:SetModified(false) - doc:SetTabText(doc:GetFileName()) - - -- activate the editor; this is needed for those cases when the editor is - -- created from some other element, for example, from a project tree. - if not skipselection then SetEditorSelection() end - - PackageEventHandle("onEditorLoad", editor) - - return editor -end - -function ReLoadFile(filePath, editor, ...) - if not editor then return LoadFile(filePath, editor, ...) end - - -- save all markers - local markers = editor:MarkerGetAll() - -- add the current line content to retrieved markers to compare later if needed - for _, marker in ipairs(markers) do marker[3] = editor:GetLineDyn(marker[1]) end - local lines = editor:GetLineCount() - - -- load file into the same editor - editor = LoadFile(filePath, editor, ...) - if not editor then return end - - if #markers > 0 then -- restore all markers - -- delete all markers as they may be restored by a different mechanism, - -- which may be limited to only restoring some markers - editor:MarkerDeleteAll(-1) - local samelinecount = lines == editor:GetLineCount() - for _, marker in ipairs(markers) do - local line, mask, text = unpack(marker) - if samelinecount then - -- restore marker at the same line number - editor:MarkerAddSet(line, mask) - else - -- find matching line in the surrounding area and restore marker there - for _, l in ipairs({line, line-1, line-2, line+1, line+2}) do - if text == editor:GetLineDyn(l) then - editor:MarkerAddSet(l, mask) - break - end - end - end - end - PackageEventHandle("onEditorMarkerUpdate", editor) - end - - return editor -end - -function ActivateFile(filename) - local name, suffix, value = filename:match('(.+):([lLpP]?)(%d+)$') - if name and not wx.wxFileExists(filename) then filename = name end - - -- check if non-existing file can be loaded from the project folder; - -- this is to handle: "project file" used on the command line - if not wx.wxFileExists(filename) and not wx.wxIsAbsolutePath(filename) then - filename = GetFullPathIfExists(ide:GetProject(), filename) or filename - end - - local opened = LoadFile(filename, nil, true) - if opened and value then - if suffix:upper() == 'P' then opened:GotoPosDelayed(tonumber(value)) - else opened:GotoPosDelayed(opened:PositionFromLine(value-1)) - end - end - return opened -end - -local function getExtsString(ed) - local exts = ed and ed.spec and ed.spec.exts or {} - local knownexts = #exts > 0 and "*."..table.concat(exts, ";*.") or nil - return (knownexts and TR("Known Files").." ("..knownexts..")|"..knownexts.."|" or "") - .. TR("All files").." (*)|*" -end - -function ReportError(msg) - return wx.wxMessageBox(msg, TR("Error"), wx.wxICON_ERROR + wx.wxOK + wx.wxCENTRE, ide.frame) -end - -function OpenFile(event) - local editor = GetEditor() - local path = editor and ide:GetDocument(editor):GetFilePath() or nil - local fileDialog = wx.wxFileDialog(ide.frame, TR("Open file"), - (path and GetPathWithSep(path) or FileTreeGetDir() or ""), - "", - getExtsString(editor), - wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST + wx.wxFD_MULTIPLE) - if fileDialog:ShowModal() == wx.wxID_OK then - for _, path in ipairs(fileDialog:GetPaths()) do - if not LoadFile(path, nil, true) then - ReportError(TR("Unable to load file '%s'."):format(path)) - end - end - end - fileDialog:Destroy() -end - --- save the file to filePath or if filePath is nil then call SaveFileAs -function SaveFile(editor, filePath) - -- this event can be aborted - -- as SaveFileAs calls SaveFile, this event may be called two times: - -- first without filePath and then with filePath - if PackageEventHandle("onEditorPreSave", editor, filePath) == false then - return false - end - - if not filePath then - return SaveFileAs(editor) - else - if ide.config.savebak then - local ok, err = FileRename(filePath, filePath..".bak") - if not ok then - ReportError(TR("Unable to save file '%s': %s"):format(filePath..".bak", err)) - return - end - end - - local st = ((editor:GetCodePage() == wxstc.wxSTC_CP_UTF8 and editor.bom or "") - .. editor:GetTextDyn()) - if GetConfigIOFilter("output") then - st = GetConfigIOFilter("output")(filePath,st) - end - - local ok, err = FileWrite(filePath, st) - if ok then - editor:SetSavePoint() - local doc = ide:GetDocument(editor) - doc.filePath = filePath - doc.fileName = wx.wxFileName(filePath):GetFullName() - doc.modTime = GetFileModTime(filePath) - doc:SetModified(false) - doc:SetTabText(doc:GetFileName()) - SetAutoRecoveryMark() - FileTreeMarkSelected(filePath) - - PackageEventHandle("onEditorSave", editor) - - return true - else - ReportError(TR("Unable to save file '%s': %s"):format(filePath, err)) - end - end - - return false -end - -function ApproveFileOverwrite() - return wx.wxMessageBox( - TR("File already exists.").."\n"..TR("Do you want to overwrite it?"), - GetIDEString("editormessage"), - wx.wxYES_NO + wx.wxCENTRE, ide.frame) == wx.wxYES -end - -function SaveFileAs(editor) - local id = editor:GetId() - local saved = false - local filePath = (openDocuments[id].filePath - or ((FileTreeGetDir() or "") - ..(openDocuments[id].fileName or ide.config.default.name))) - - local fn = wx.wxFileName(filePath) - fn:Normalize() -- want absolute path for dialog - - local ext = fn:GetExt() - if (not ext or #ext == 0) and editor.spec and editor.spec.exts then - ext = editor.spec.exts[1] - -- set the extension on the file if assigned as this is used by OSX/Linux - -- to present the correct default "save as type" choice. - if ext then fn:SetExt(ext) end - end - local fileDialog = wx.wxFileDialog(ide.frame, TR("Save file as"), - fn:GetPath(wx.wxPATH_GET_VOLUME), - fn:GetFullName(), - -- specify the current extension plus all other extensions based on specs - (ext and #ext > 0 and "*."..ext.."|*."..ext.."|" or "")..getExtsString(editor), - wx.wxFD_SAVE) - - if fileDialog:ShowModal() == wx.wxID_OK then - local filePath = fileDialog:GetPath() - - -- check if there is another tab with the same name and prepare to close it - local existing = (ide:FindDocument(filePath) or {}).index - local cansave = fn:GetFullName() == filePath -- saving into the same file - or not wx.wxFileName(filePath):FileExists() -- or a new file - or ApproveFileOverwrite() - - if cansave and SaveFile(editor, filePath) then - SetEditorSelection() -- update title of the editor - if ext ~= GetFileExt(filePath) then - -- new extension, so setup new keywords and re-apply indicators - editor:ClearDocumentStyle() -- remove styles from the document - editor:SetupKeywords(GetFileExt(filePath)) - IndicateAll(editor) - IndicateFunctionsOnly(editor) - MarkupStyle(editor) - end - saved = true - - if existing then - -- save the current selection as it may change after closing - local current = notebook:GetSelection() - ClosePage(existing) - -- restore the selection if it changed - if current ~= notebook:GetSelection() then - notebook:SetSelection(current) - end - end - end - end - - fileDialog:Destroy() - return saved -end - -function SaveAll(quiet) - for _, document in pairs(openDocuments) do - local editor = document.editor - local filePath = document.filePath - - if (document.isModified or not document.filePath) -- need to save - and (document.filePath or not quiet) then -- have path or can ask user - SaveFile(editor, filePath) -- will call SaveFileAs if necessary - end - end -end - -local function removePage(index) - local prevIndex = nil - local nextIndex = nil - - -- try to preserve old selection - local selectIndex = notebook:GetSelection() - selectIndex = selectIndex ~= index and selectIndex - - local delid = nil - for id, document in pairsSorted(openDocuments, - function(a, b) -- sort by document index - return openDocuments[a].index < openDocuments[b].index - end) do - local wasselected = document.index == selectIndex - if document.index < index then - prevIndex = document.index - elseif document.index == index then - delid = id - document.editor:Destroy() - elseif document.index > index then - document.index = document.index - 1 - if nextIndex == nil then - nextIndex = document.index - end - end - if (wasselected) then - selectIndex = document.index - end - end - - if (delid) then - openDocuments[delid] = nil - end - - notebook:RemovePage(index) - - if selectIndex then - notebook:SetSelection(selectIndex) - elseif nextIndex then - notebook:SetSelection(nextIndex) - elseif prevIndex then - notebook:SetSelection(prevIndex) - end - - -- need to set editor selection as it's called *after* PAGE_CHANGED event - SetEditorSelection() -end - -function ClosePage(selection) - local editor = GetEditor(selection) - local id = editor:GetId() - - if PackageEventHandle("onEditorPreClose", editor) == false then - return false - end - - if SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL then - DynamicWordsRemoveAll(editor) - local debugger = ide.debugger - -- check if the window with the scratchpad running is being closed - if debugger and debugger.scratchpad and debugger.scratchpad.editors - and debugger.scratchpad.editors[editor] then - DebuggerScratchpadOff() - end - -- check if the debugger is running and is using the current window; - -- abort the debugger if the current marker is in the window being closed - if debugger and debugger.server and - (editor:MarkerNext(0, CURRENT_LINE_MARKER_VALUE) >= 0) then - debugger.terminate() - end - PackageEventHandle("onEditorClose", editor) - removePage(ide.openDocuments[id].index) - - -- disable full screen if the last tab is closed - if not (notebook:GetSelection() >= 0) then ShowFullScreen(false) end - return true - end - return false -end - -function CloseAllPagesExcept(selection) - local toclose = {} - for _, document in pairs(ide.openDocuments) do - table.insert(toclose, document.index) - end - - table.sort(toclose) - - -- close pages for those files that match the project in the reverse order - -- (as ids shift when pages are closed) - for i = #toclose, 1, -1 do - if toclose[i] ~= selection then ClosePage(toclose[i]) end - end -end - --- Show a dialog to save a file before closing editor. --- returns wxID_YES, wxID_NO, or wxID_CANCEL if allow_cancel -function SaveModifiedDialog(editor, allow_cancel) - local result = wx.wxID_NO - local id = editor:GetId() - local document = openDocuments[id] - local filePath = document.filePath - local fileName = document.fileName - if document.isModified then - local message = TR("Do you want to save the changes to '%s'?") - :format(fileName or ide.config.default.name) - local dlg_styles = wx.wxYES_NO + wx.wxCENTRE + wx.wxICON_QUESTION - if allow_cancel then dlg_styles = dlg_styles + wx.wxCANCEL end - local dialog = wx.wxMessageDialog(ide.frame, message, - TR("Save Changes?"), - dlg_styles) - result = dialog:ShowModal() - dialog:Destroy() - if result == wx.wxID_YES then - if not SaveFile(editor, filePath) then - return wx.wxID_CANCEL -- cancel if canceled save dialog - end - end - end - - return result -end - -function SaveOnExit(allow_cancel) - for _, document in pairs(openDocuments) do - if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then - return false - end - end - - -- if all documents have been saved or refused to save, then mark those that - -- are still modified as not modified (they don't need to be saved) - -- to keep their tab names correct - for _, document in pairs(openDocuments) do - if document.isModified then document:SetModified(false) end - end - - return true -end - -function SetAllEditorsReadOnly(enable) - for _, document in pairs(openDocuments) do - document.editor:SetReadOnly(enable) - end -end - ------------------ --- Debug related - -function ClearAllCurrentLineMarkers() - for _, document in pairs(openDocuments) do - document.editor:MarkerDeleteAll(CURRENT_LINE_MARKER) - document.editor:Refresh() -- needed for background markers that don't get refreshed (wx2.9.5) - end -end - --- remove shebang line (#!) as it throws a compilation error as --- loadstring() doesn't allow it even though lua/loadfile accepts it. --- replace with a new line to keep the number of lines the same. -function StripShebang(code) return (code:gsub("^#!.-\n", "\n")) end - -local compileOk, compileTotal = 0, 0 -function CompileProgram(editor, params) - local params = { - jumponerror = (params or {}).jumponerror ~= false, - reportstats = (params or {}).reportstats ~= false, - keepoutput = (params or {}).keepoutput, - } - local doc = ide:GetDocument(editor) - local filePath = doc:GetFilePath() or doc:GetFileName() - local func, err = loadstring(StripShebang(editor:GetTextDyn()), '@'..filePath) - local line = not func and tonumber(err:match(":(%d+)%s*:")) or nil - - if not params.keepoutput then ClearOutput() end - - compileTotal = compileTotal + 1 - if func then - compileOk = compileOk + 1 - if params.reportstats then - DisplayOutputLn(TR("Compilation successful; %.0f%% success rate (%d/%d).") - :format(compileOk/compileTotal*100, compileOk, compileTotal)) - end - else - ActivateOutput() - DisplayOutputLn(TR("Compilation error").." "..TR("on line %d"):format(line)..":") - DisplayOutputLn((err:gsub("\n$", ""))) - -- check for escapes invalid in LuaJIT/Lua 5.2 that are allowed in Lua 5.1 - if err:find('invalid escape sequence') then - local s = editor:GetLineDyn(line-1) - local cleaned = s - :gsub('\\[abfnrtv\\"\']', ' ') - :gsub('(\\x[0-9a-fA-F][0-9a-fA-F])', function(s) return string.rep(' ', #s) end) - :gsub('(\\%d%d?%d?)', function(s) return string.rep(' ', #s) end) - :gsub('(\\z%s*)', function(s) return string.rep(' ', #s) end) - local invalid = cleaned:find("\\") - if invalid then - DisplayOutputLn(TR("Consider removing backslash from escape sequence '%s'.") - :format(s:sub(invalid,invalid+1))) - end - end - if line and params.jumponerror and line-1 ~= editor:GetCurrentLine() then - editor:GotoLine(line-1) - end - end - - return func ~= nil -- return true if it compiled ok -end - ------------------- --- Save & Close - -function SaveIfModified(editor) - local id = editor:GetId() - if openDocuments[id].isModified then - local saved = false - if not openDocuments[id].filePath then - local ret = wx.wxMessageBox( - TR("You must save the program first.").."\n"..TR("Press cancel to abort."), - TR("Save file?"), wx.wxOK + wx.wxCANCEL + wx.wxCENTRE, ide.frame) - if ret == wx.wxOK then - saved = SaveFileAs(editor) - end - else - saved = SaveFile(editor, openDocuments[id].filePath) - end - - if saved then - openDocuments[id].isModified = false - else - return false -- not saved - end - end - - return true -- saved -end - -function GetOpenFiles() - local opendocs = {} - for _, document in pairs(ide.openDocuments) do - if (document.filePath) then - local wxfname = wx.wxFileName(document.filePath) - wxfname:Normalize() - - table.insert(opendocs, {filename=wxfname:GetFullPath(), - id=document.index, cursorpos = document.editor:GetCurrentPos()}) - end - end - - -- to keep tab order - table.sort(opendocs,function(a,b) return (a.id < b.id) end) - - local id = GetEditor() - id = id and id:GetId() - return opendocs, {index = (id and openDocuments[id].index or 0)} -end - -function SetOpenFiles(nametab,params) - for _, doc in ipairs(nametab) do - local editor = LoadFile(doc.filename,nil,true,true) -- skip selection - if editor then editor:GotoPosDelayed(doc.cursorpos or 0) end - end - notebook:SetSelection(params and params.index or 0) - SetEditorSelection() -end - -local beforeFullScreenPerspective -local statusbarShown - -function ShowFullScreen(setFullScreen) - if setFullScreen then - beforeFullScreenPerspective = uimgr:SavePerspective() - - local panes = frame.uimgr:GetAllPanes() - for index = 0, panes:GetCount()-1 do - local name = panes:Item(index).name - if name ~= "notebook" then frame.uimgr:GetPane(name):Hide() end - end - uimgr:Update() - SetEditorSelection() -- make sure the focus is on the editor - elseif beforeFullScreenPerspective then - uimgr:LoadPerspective(beforeFullScreenPerspective, true) - beforeFullScreenPerspective = nil - end - - -- On OSX, status bar is not hidden when switched to - -- full screen: http://trac.wxwidgets.org/ticket/14259; do manually. - -- need to turn off before showing full screen and turn on after, - -- otherwise the window is restored incorrectly and is reduced in size. - if ide.osname == 'Macintosh' and setFullScreen then - statusbarShown = frame:GetStatusBar():IsShown() - frame:GetStatusBar():Hide() - end - - -- protect from systems that don't have ShowFullScreen (GTK on linux?) - pcall(function() frame:ShowFullScreen(setFullScreen) end) - - if ide.osname == 'Macintosh' and not setFullScreen then - if statusbarShown then - frame:GetStatusBar():Show() - -- refresh AuiManager as the statusbar may be shown below the border - uimgr:Update() - end - end -end - -function ProjectConfig(dir, config) - if config then ide.session.projects[dir] = config - else return unpack(ide.session.projects[dir] or {}) end -end - -function SetOpenTabs(params) - local recovery, nametab = LoadSafe("return "..params.recovery) - if not recovery or not nametab then - DisplayOutputLn(TR("Can't process auto-recovery record; invalid format: %s."):format(nametab)) - return - end - if not params.quiet then - DisplayOutputLn(TR("Found auto-recovery record and restored saved session.")) - end - for _,doc in ipairs(nametab) do - -- check for missing file if no content is stored - if doc.filepath and not doc.content and not wx.wxFileExists(doc.filepath) then - DisplayOutputLn(TR("File '%s' is missing and can't be recovered.") - :format(doc.filepath)) - else - local editor = (doc.filepath and LoadFile(doc.filepath,nil,true,true) - or findUnusedEditor() or NewFile(doc.filename)) - local opendoc = ide:GetDocument(editor) - if doc.content then - editor:SetTextDyn(doc.content) - if doc.filepath and opendoc.modTime and doc.modified < opendoc.modTime:GetTicks() then - DisplayOutputLn(TR("File '%s' has more recent timestamp than restored '%s'; please review before saving.") - :format(doc.filepath, opendoc:GetTabText())) - end - opendoc:SetModified(true) - end - editor:GotoPosDelayed(doc.cursorpos or 0) - end - end - notebook:SetSelection(params and params.index or 0) - SetEditorSelection() -end - -local function getOpenTabs() - local opendocs = {} - for _, document in pairs(ide.openDocuments) do - local editor = document:GetEditor() - table.insert(opendocs, { - filename = document:GetFileName(), - filepath = document:GetFilePath(), - tabname = document:GetTabText(), - modified = document:GetModTime() and document:GetModTime():GetTicks(), -- get number of seconds - content = document:IsModified() and editor:GetTextDyn() or nil, - id = document:GetTabIndex(), - cursorpos = editor:GetCurrentPos()}) - end - - -- to keep tab order - table.sort(opendocs, function(a,b) return (a.id < b.id) end) - - local ed = GetEditor() - local doc = ed and ide:GetDocument(ed) - return opendocs, {index = (doc and doc:GetTabIndex() or 0)} -end - -function SetAutoRecoveryMark() - ide.session.lastupdated = os.time() -end - -local function generateRecoveryRecord(opentabs) - return require('mobdebug').line(opentabs, {comment = false}) -end - -local function saveHotExit() - local opentabs, params = getOpenTabs() - if #opentabs > 0 then - params.recovery = generateRecoveryRecord(opentabs) - params.quiet = true - SettingsSaveFileSession({}, params) - end -end - -local function saveAutoRecovery(force) - if not ide.config.autorecoverinactivity then return end - - local lastupdated = ide.session.lastupdated - if not force then - if not lastupdated or lastupdated < (ide.session.lastsaved or 0) then return end - end - - local now = os.time() - if not force and lastupdated + ide.config.autorecoverinactivity > now then return end - - -- find all open modified files and save them - local opentabs, params = getOpenTabs() - if #opentabs > 0 then - params.recovery = generateRecoveryRecord(opentabs) - SettingsSaveAll() - SettingsSaveFileSession({}, params) - ide.settings:Flush() - end - ide.session.lastsaved = now - ide:SetStatus(TR("Saved auto-recover at %s."):format(os.date("%H:%M:%S"))) -end - -local function fastWrap(func, ...) - -- ignore SetEditorSelection that is not needed as `func` may work on - -- multipe files, but editor needs to be selected once. - local SES = SetEditorSelection - SetEditorSelection = function() end - func(...) - SetEditorSelection = SES -end - -function StoreRestoreProjectTabs(curdir, newdir, intfname) - local win = ide.osname == 'Windows' - local interpreter = intfname or ide.interpreter.fname - local current, closing, restore = notebook:GetSelection(), 0, false - - if ide.osname ~= 'Macintosh' then notebook:Freeze() end - - if curdir and #curdir > 0 then - local lowcurdir = win and string.lower(curdir) or curdir - local lownewdir = win and string.lower(newdir) or newdir - local projdocs, closdocs = {}, {} - for _, document in ipairs(GetOpenFiles()) do - local dpath = win and string.lower(document.filename) or document.filename - -- check if the filename is in the same folder - if dpath:find(lowcurdir, 1, true) == 1 - and dpath:find("^[\\/]", #lowcurdir+1) then - table.insert(projdocs, document) - closing = closing + (document.id < current and 1 or 0) - -- only close if the file is not in new project as it would be reopened - if not dpath:find(lownewdir, 1, true) - or not dpath:find("^[\\/]", #lownewdir+1) then - table.insert(closdocs, document) - end - elseif document.id == current then restore = true end - end - - -- adjust for the number of closing tabs on the left from the current one - current = current - closing - - -- save opened files from this project - ProjectConfig(curdir, {projdocs, - {index = notebook:GetSelection() - current, interpreter = interpreter}}) - - -- close pages for those files that match the project in the reverse order - -- (as ids shift when pages are closed) - for i = #closdocs, 1, -1 do fastWrap(ClosePage, closdocs[i].id) end - end - - local files, params = ProjectConfig(newdir) - if files then - -- provide fake index so that it doesn't activate it as the index may be not - -- quite correct if some of the existing files are already open in the IDE. - fastWrap(SetOpenFiles, files, {index = #files + notebook:GetPageCount()}) - end - - -- either interpreter is chosen for the project or the default value is set - if (params and params.interpreter) or (not params and ide.config.interpreter) then - ProjectSetInterpreter(params and params.interpreter or ide.config.interpreter) - end - - if ide.osname ~= 'Macintosh' then notebook:Thaw() end - - local index = params and params.index - if notebook:GetPageCount() == 0 then NewFile() - elseif restore and current >= 0 then notebook:SetSelection(current) - elseif index and index >= 0 and files[index+1] then - -- move the editor tab to the front with the file from the config - LoadFile(files[index+1].filename, nil, true) - SetEditorSelection() -- activate the editor in the active tab - end - - -- remove current config as it may change; the current configuration is - -- stored with the general config. - -- The project configuration will be updated when the project is changed. - ProjectConfig(newdir, {}) -end - -local function closeWindow(event) - -- if the app is already exiting, then help it exit; wxwidgets on Windows - -- is supposed to report Shutdown/logoff events by setting CanVeto() to - -- false, but it doesn't happen. We simply leverage the fact that - -- CloseWindow is called several times in this case and exit. Similar - -- behavior has been also seen on Linux, so this logic applies everywhere. - if ide.exitingProgram then os.exit() end - - ide.exitingProgram = true -- don't handle focus events - - if not ide.config.hotexit and not SaveOnExit(event:CanVeto()) then - event:Veto() - ide.exitingProgram = false - return - end - - ShowFullScreen(false) - - PackageEventHandle("onAppClose") - - -- first need to detach all processes IDE has launched as the current - -- process is likely to terminate before child processes are terminated, - -- which may lead to a crash when EVT_END_PROCESS event is called. - DetachChildProcess() - DebuggerShutdown() - - SettingsSaveAll() - if ide.config.hotexit then saveHotExit() end - ide.settings:Flush() - - do -- hide all floating panes first - local panes = frame.uimgr:GetAllPanes() - for index = 0, panes:GetCount()-1 do - local pane = frame.uimgr:GetPane(panes:Item(index).name) - if pane:IsFloating() then pane:Hide() end - end - end - frame.uimgr:Update() -- hide floating panes - frame.uimgr:UnInit() - frame:Hide() -- hide the main frame while the IDE exits - - -- stop all the timers - for _, timer in pairs(ide.timers) do timer:Stop() end - - event:Skip() - - PackageEventHandle("onAppDone") -end -frame:Connect(wx.wxEVT_CLOSE_WINDOW, closeWindow) - -frame:Connect(wx.wxEVT_TIMER, function() saveAutoRecovery() end) - --- in the presence of wxAuiToolbar, when (1) the app gets focus, --- (2) a floating panel is closed or (3) a toolbar dropdown is closed, --- the focus is always on the toolbar when the app gets focus, --- so to restore the focus correctly, need to track where the control is --- and to set the focus to the last element that had focus. --- it would be easier to track KILL_FOCUS events, but controls on OSX --- don't always generate KILL_FOCUS events (see relevant wxwidgets --- tickets: http://trac.wxwidgets.org/ticket/14142 --- and http://trac.wxwidgets.org/ticket/14269) - -ide.editorApp:Connect(wx.wxEVT_SET_FOCUS, function(event) - if ide.exitingProgram then return end - - local win = ide.frame:FindFocus() - if win then - local class = win:GetClassInfo():GetClassName() - -- don't set focus on the main frame or toolbar - if ide.infocus and (class == 'wxAuiToolBar' or class == 'wxFrame') then - -- check if the window is shown before returning focus to it, - -- as it may lead to a recursion in event handlers on OSX (wxwidgets 2.9.5). - pcall(function() if ide:IsWindowShown(ide.infocus) then ide.infocus:SetFocus() end end) - return - end - - -- keep track of the current control in focus, but only on the main frame - -- don't try to "remember" any of the focus changes on various dialog - -- windows as those will disappear along with their controls - local grandparent = win:GetGrandParent() - local frameid = ide.frame:GetId() - local mainwin = grandparent and grandparent:GetId() == frameid - local parent = win:GetParent() - while parent do - local class = parent:GetClassInfo():GetClassName() - if (class == 'wxFrame' or class:find('^wx.*Dialog$')) - and parent:GetId() ~= frameid then - mainwin = false; break - end - parent = parent:GetParent() - end - if mainwin then - if ide.infocus and ide.infocus ~= win and ide.osname == 'Macintosh' then - -- kill focus on the control that had the focus as wxwidgets on OSX - -- doesn't do it: http://trac.wxwidgets.org/ticket/14142; - -- wrap into pcall in case the window is already deleted - local ev = wx.wxFocusEvent(wx.wxEVT_KILL_FOCUS) - pcall(function() ide.infocus:GetEventHandler():ProcessEvent(ev) end) - end - ide.infocus = win - end - end - - event:Skip() -end) - -local updateInterval = 250 -- time in ms -wx.wxUpdateUIEvent.SetUpdateInterval(updateInterval) - -ide.editorApp:Connect(wx.wxEVT_ACTIVATE_APP, - function(event) - if not ide.exitingProgram then - if ide.osname == 'Macintosh' and ide.infocus and event:GetActive() then - -- restore focus to the last element that received it; - -- wrap into pcall in case the element has disappeared - -- while the application was out of focus - pcall(function() if ide:IsWindowShown(ide.infocus) then ide.infocus:SetFocus() end end) - end - - local active = event:GetActive() - -- save auto-recovery record when making the app inactive - if not active then saveAutoRecovery(true) end - - -- disable UI refresh when app is inactive, but only when not running - wx.wxUpdateUIEvent.SetUpdateInterval( - (active or ide:GetLaunchedProcess()) and updateInterval or -1) - - PackageEventHandle(active and "onAppFocusSet" or "onAppFocusLost", ide.editorApp) - end - event:Skip() - end) - -if ide.config.autorecoverinactivity then - ide.timers.session = wx.wxTimer(frame) - -- check at least 5s to be never more than 5s off - ide.timers.session:Start(math.min(5, ide.config.autorecoverinactivity)*1000) -end - -function PaneFloatToggle(window) - local pane = uimgr:GetPane(window) - if pane:IsFloating() then - pane:Dock() - else - pane:Float() - pane:FloatingPosition(pane.window:GetScreenPosition()) - pane:FloatingSize(pane.window:GetSize()) - end - uimgr:Update() -end - -local cma, cman = 0, 1 -frame:Connect(wx.wxEVT_IDLE, - function(event) - local debugger = ide.debugger - if (debugger.update) then debugger.update() end - if (debugger.scratchpad) then DebuggerRefreshScratchpad() end - if IndicateIfNeeded() then event:RequestMore(true) end - PackageEventHandleOnce("onIdleOnce", event) - PackageEventHandle("onIdle", event) - - -- process onidle events if any - if #ide.onidle > 0 then table.remove(ide.onidle)() end - if #ide.onidle > 0 then event:RequestMore(true) end -- request more if anything left - - if ide.config.showmemoryusage then - local mem = collectgarbage("count") - local alpha = math.max(tonumber(ide.config.showmemoryusage) or 0, 1/cman) - cman = cman + 1 - cma = alpha * mem + (1-alpha) * cma - ide:SetStatus(("cur: %sKb; avg: %sKb"):format(math.floor(mem), math.floor(cma))) - end - - event:Skip() -- let other EVT_IDLE handlers to work on the event - end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/debugger.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/debugger.lua deleted file mode 100644 index 26209c1..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/debugger.lua +++ /dev/null @@ -1,1696 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- Original authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) --- Integration with MobDebug ---------------------------------------------------------- - -local copas = require "copas" -local socket = require "socket" -local mobdebug = require "mobdebug" -local unpack = table.unpack or unpack - -local ide = ide -local debugger = setmetatable(ide.debugger, ide.proto.Debugger) -debugger.server = nil -- DebuggerServer object when debugging, else nil -debugger.running = false -- true when the debuggee is running -debugger.listening = false -- true when the debugger is listening for a client -debugger.portnumber = ide.config.debugger.port or mobdebug.port -- the port # to use for debugging -debugger.watchCtrl = nil -- the watch ctrl that shows watch information -debugger.stackCtrl = nil -- the stack ctrl that shows stack information -debugger.toggleview = { - bottomnotebook = true, -- output/console is "on" by default - stackpanel = false, watchpanel = false, toolbar = false } -debugger.needrefresh = {} -- track components that may need a refresh -debugger.hostname = ide.config.debugger.hostname or (function() - local hostname = socket.dns.gethostname() - return hostname and socket.dns.toip(hostname) and hostname or "localhost" -end)() -debugger.imglist = ide:CreateImageList("STACK", "VALUE-CALL", "VALUE-LOCAL", "VALUE-UP") - -local image = { STACK = 0, LOCAL = 1, UPVALUE = 2 } -local notebook = ide.frame.notebook - -local CURRENT_LINE_MARKER = StylesGetMarker("currentline") -local CURRENT_LINE_MARKER_VALUE = 2^CURRENT_LINE_MARKER -local BREAKPOINT_MARKER = StylesGetMarker("breakpoint") -local BREAKPOINT_MARKER_VALUE = 2^BREAKPOINT_MARKER - -local activate = {CHECKONLY = 1, NOREPORT = 2} - -local function serialize(value, options) return mobdebug.line(value, options) end - -local stackmaxlength = ide.config.debugger.maxdatalength -local stackmaxnum = ide.config.debugger.maxdatanum -local stackmaxlevel = ide.config.debugger.maxdatalevel -local params = {comment = false, nocode = true, maxlevel = stackmaxlevel, maxnum = stackmaxnum} - -local function fixUTF8(...) - local t = {...} - -- convert to escaped decimal code as these can only appear in strings - local function fix(s) return '\\'..string.byte(s) end - for i = 1, #t do t[i] = FixUTF8(t[i], fix) end - return unpack(t) -end - -local function trimToMaxLength(...) - local t = {...} - for i = 1, #t do - t[i] = t[i]:sub(1, stackmaxlength)..(#t[i] > stackmaxlength and '...' or '') - end - return unpack(t) -end - -local q = EscapeMagic - -local function updateWatchesSync(onlyitem) - local watchCtrl = debugger.watchCtrl - local pane = ide.frame.uimgr:GetPane("watchpanel") - local shown = watchCtrl and (pane:IsOk() and pane:IsShown() or not pane:IsOk() and watchCtrl:IsShown()) - local canupdate = (debugger.server and not debugger.running and not debugger.scratchpad - and not (debugger.options or {}).noeval) - if shown and canupdate then - local bgcl = watchCtrl:GetBackgroundColour() - local hicl = wx.wxColour(math.floor(bgcl:Red()*.9), - math.floor(bgcl:Green()*.9), math.floor(bgcl:Blue()*.9)) - - local root = watchCtrl:GetRootItem() - if not root or not root:IsOk() then return end - - local item = onlyitem or watchCtrl:GetFirstChild(root) - while true do - if not item:IsOk() then break end - - local expression = watchCtrl:GetItemExpression(item) - if expression then - local _, values, error = debugger.evaluate(expression) - local curchildren = watchCtrl:GetItemChildren(item) - if error then - error = error:gsub("%[.-%]:%d+:%s+","") - watchCtrl:SetItemValueIfExpandable(item, nil) - else - if #values == 0 then values = {'nil'} end - local _, res = LoadSafe("return "..values[1]) - watchCtrl:SetItemValueIfExpandable(item, res) - end - - local newval = (expression .. ' = ' - .. (error and ('error: '..error) or table.concat(values, ", "))) - local val = watchCtrl:GetItemText(item) - - watchCtrl:SetItemBackgroundColour(item, val ~= newval and hicl or bgcl) - watchCtrl:SetItemText(item, newval) - - if onlyitem or val ~= newval then - local newchildren = watchCtrl:GetItemChildren(item) - if next(curchildren) ~= nil and next(newchildren) == nil then - watchCtrl:SetItemHasChildren(item, true) - watchCtrl:CollapseAndReset(item) - watchCtrl:SetItemHasChildren(item, false) - elseif next(curchildren) ~= nil and next(newchildren) ~= nil then - watchCtrl:CollapseAndReset(item) - watchCtrl:Expand(item) - end - end - end - - if onlyitem then break end - item = watchCtrl:GetNextSibling(item) - end - elseif not shown and canupdate then - debugger.needrefresh.watches = true - end -end - -local simpleType = {['nil'] = true, ['string'] = true, ['number'] = true, ['boolean'] = true} -local callData = {} - -local function updateStackSync() - local stackCtrl = debugger.stackCtrl - local pane = ide.frame.uimgr:GetPane("stackpanel") - local shown = stackCtrl and (pane:IsOk() and pane:IsShown() or not pane:IsOk() and stackCtrl:IsShown()) - local canupdate = debugger.server and not debugger.running and not debugger.scratchpad - if shown and canupdate then - local stack, _, err = debugger.stack() - if not stack or #stack == 0 then - stackCtrl:DeleteAll() - if err then -- report an error if any - stackCtrl:AppendItem(stackCtrl:AddRoot("Stack"), "Error: " .. err, image.STACK) - end - return - end - stackCtrl:Freeze() - stackCtrl:DeleteAll() - - local root = stackCtrl:AddRoot("Stack") - callData = {} -- reset call cache - for _,frame in ipairs(stack) do - -- "main chunk at line 24" - -- "foo() at line 13 (defined at foobar.lua:11)" - -- call = { source.name, source.source, source.linedefined, - -- source.currentline, source.what, source.namewhat, source.short_src } - local call = frame[1] - - -- format the function name to a readable user string - local func = call[5] == "main" and "main chunk" - or call[5] == "C" and (call[1] or "C function") - or call[5] == "tail" and "tail call" - or (call[1] or "anonymous function") - - -- format the function treeitem text string, including the function name - local text = func .. - (call[4] == -1 and '' or " at line "..call[4]) .. - (call[5] ~= "main" and call[5] ~= "Lua" and '' - or (call[3] > 0 and " (defined at "..call[7]..":"..call[3]..")" - or " (defined in "..call[7]..")")) - - -- create the new tree item for this level of the call stack - local callitem = stackCtrl:AppendItem(root, text, image.STACK) - - -- register call data to provide stack navigation - callData[callitem:GetValue()] = { call[2], call[4] } - - -- add the local variables to the call stack item - for name,val in pairs(frame[2]) do - -- format the variable name, value as a single line and, - -- if not a simple type, the string value. - - -- comment can be not necessarily a string for tables with metatables - -- that provide its own __tostring method - local value, comment = val[1], fixUTF8(trimToMaxLength(tostring(val[2]))) - local text = ("%s = %s%s"): - format(name, fixUTF8(trimToMaxLength(serialize(value, params))), - (simpleType[type(value)] or not val[2]) and "" or (" --[["..comment.."]]")) - local item = stackCtrl:AppendItem(callitem, text, image.LOCAL) - stackCtrl:SetItemValueIfExpandable(item, value) - end - - -- add the upvalues for this call stack level to the tree item - for name,val in pairs(frame[3]) do - local value, comment = val[1], fixUTF8(trimToMaxLength(tostring(val[2]))) - local text = ("%s = %s%s"): - format(name, fixUTF8(trimToMaxLength(serialize(value, params))), - (simpleType[type(value)] or not val[2]) and "" or (" --[["..comment.."]]")) - local item = stackCtrl:AppendItem(callitem, text, image.UPVALUE) - stackCtrl:SetItemValueIfExpandable(item, value) - end - - stackCtrl:SortChildren(callitem) - stackCtrl:Expand(callitem) - end - stackCtrl:EnsureVisible(stackCtrl:GetFirstChild(root)) - stackCtrl:SetScrollPos(wx.wxHORIZONTAL, 0, true) - stackCtrl:Thaw() - elseif not shown and canupdate then - debugger.needrefresh.stack = true - end -end - -local function updateStackAndWatches() - -- check if the debugger is running and may be waiting for a response. - -- allow that request to finish, otherwise this function does nothing. - if debugger.running then debugger.update() end - if debugger.server and not debugger.running then - copas.addthread(function() updateStackSync() updateWatchesSync() end) - end -end - -local function updateWatches(item) - -- check if the debugger is running and may be waiting for a response. - -- allow that request to finish, otherwise this function does nothing. - if debugger.running then debugger.update() end - if debugger.server and not debugger.running then - copas.addthread(function() updateWatchesSync(item) end) - end -end - -local function updateStack() - -- check if the debugger is running and may be waiting for a response. - -- allow that request to finish, otherwise this function does nothing. - if debugger.running then debugger.update() end - if debugger.server and not debugger.running then - copas.addthread(function() updateStackSync() end) - end -end - -local function debuggerToggleViews(show) - -- don't toggle if the current state is the same as the new one - local shown = debugger.toggleview.shown - if (show and shown) or (not show and not shown) then return end - - debugger.toggleview.shown = nil - - local mgr = ide.frame.uimgr - local refresh = false - for view, needed in pairs(debugger.toggleview) do - local bar = view == 'toolbar' - local pane = mgr:GetPane(view) - if show then -- starting debugging and pane is not shown - debugger.toggleview[view] = not pane:IsShown() - if debugger.toggleview[view] and (needed or bar) - and (not bar or not ide.frame:IsFullScreen()) then - pane:Show() - refresh = true - end - else -- completing debugging and pane is shown - debugger.toggleview[view] = pane:IsShown() and needed - if debugger.toggleview[view] then - pane:Hide() - refresh = true - end - end - end - if refresh then mgr:Update() end - if show then debugger.toggleview.shown = true end -end - -local function killClient() - if (debugger.pid and wx.wxProcess.Exists(debugger.pid)) then - -- using SIGTERM for some reason kills not only the debugee process, - -- but also some system processes, which leads to a blue screen crash - -- (at least on Windows Vista SP2) - local ret = wx.wxProcess.Kill(debugger.pid, wx.wxSIGKILL, wx.wxKILL_CHILDREN) - if ret == wx.wxKILL_OK then - DisplayOutputLn(TR("Program stopped (pid: %d)."):format(debugger.pid)) - elseif ret ~= wx.wxKILL_NO_PROCESS then - DisplayOutputLn(TR("Unable to stop program (pid: %d), code %d.") - :format(debugger.pid, ret)) - end - end - debugger.pid = nil -end - -local function activateDocument(file, line, activatehow) - if not file then return end - - -- file can be a filename or serialized file content; deserialize first. - -- check if the filename starts with '"' and is deserializable - -- to avoid showing filenames that may look like valid lua code - -- (for example: 'mobdebug.lua'). - local content - if not wx.wxFileName(file):FileExists() and file:find('^"') then - local ok, res = LoadSafe("return "..file) - if ok then content = res end - end - - -- in some cases filename can be returned quoted if the chunk is loaded with - -- loadstring(chunk, "filename") instead of loadstring(chunk, "@filename") - if content then - -- if the returned content can be matched with a file, it's a file name - local fname = GetFullPathIfExists(debugger.basedir, content) or content - if wx.wxFileName(fname):FileExists() then file, content = fname, nil end - elseif not wx.wxIsAbsolutePath(file) and debugger.basedir then - file = debugger.basedir .. file - end - - local activated - local indebugger = file:find('mobdebug%.lua$') - local fileName = wx.wxFileName(file) - - for _, document in pairs(ide.openDocuments) do - local editor = document.editor - -- either the file name matches, or the content; - -- when checking for the content remove all newlines as they may be - -- reported differently from the original by the Lua engine. - if document.filePath and fileName:SameAs(wx.wxFileName(document.filePath)) - or content and content:gsub("[\n\r]","") == editor:GetTextDyn():gsub("[\n\r]","") then - ClearAllCurrentLineMarkers() - if line then - if line == 0 then -- special case; find the first executable line - line = math.huge - local func = loadstring(editor:GetTextDyn()) - if func then -- .activelines == {[3] = true, [4] = true, ...} - for l in pairs(debug.getinfo(func, "L").activelines) do - if l < line then line = l end - end - end - if line == math.huge then line = 1 end - end - local line = line - 1 -- editor line operations are zero-based - if debugger.runtocursor then - local ed, ln = unpack(debugger.runtocursor) - if ed:GetId() == editor:GetId() and ln == line then - DebuggerToggleBreakpoint(ed, ln) - debugger.runtocursor = nil - end - end - editor:MarkerAdd(line, CURRENT_LINE_MARKER) - editor:Refresh() -- needed for background markers that don't get refreshed (wx2.9.5) - - -- expand fold if the activated line is in a folded fragment - if not editor:GetLineVisible(line) then editor:ToggleFold(editor:GetFoldParent(line)) end - - -- found and marked what we are looking for; - -- don't need to activate with CHECKONLY (this assumes line is given) - if activatehow == activate.CHECKONLY then return editor end - - local firstline = editor:DocLineFromVisible(editor:GetFirstVisibleLine()) - local lastline = math.min(editor:GetLineCount(), - editor:DocLineFromVisible(editor:GetFirstVisibleLine() + editor:LinesOnScreen())) - -- if the line is already on the screen, then don't enforce policy - if line <= firstline or line >= lastline then - editor:EnsureVisibleEnforcePolicy(line) - end - end - - local selection = document.index - RequestAttention() - notebook:SetSelection(selection) - SetEditorSelection(selection) - - if content then - -- it's possible that the current editor tab already has - -- breakpoints that have been set based on its filepath; - -- if the content has been matched, then existing breakpoints - -- need to be removed and new ones set, based on the content. - if not debugger.editormap[editor] and document.filePath then - local filePath = document.filePath - local line = editor:MarkerNext(0, BREAKPOINT_MARKER_VALUE) - while filePath and line ~= -1 do - debugger.handle("delb " .. filePath .. " " .. (line+1)) - debugger.handle("setb " .. file .. " " .. (line+1)) - line = editor:MarkerNext(line + 1, BREAKPOINT_MARKER_VALUE) - end - end - - -- keep track of those editors that have been activated based on - -- content rather than file names as their breakpoints have to be - -- specified in a different way - debugger.editormap[editor] = file - end - - activated = editor - break - end - end - - if not (activated or indebugger or debugger.loop or activatehow == activate.CHECKONLY) - and (ide.config.editor.autoactivate or content and activatehow == activate.NOREPORT) then - -- found file, but can't activate yet (because this part may be executed - -- in a different coroutine), so schedule pending activation. - if content or wx.wxFileName(file):FileExists() then - debugger.activate = {file, line, content} - return true -- report successful activation, even though it's pending - end - - -- only report files once per session and if not asked to skip - if not debugger.missing[file] and activatehow ~= activate.NOREPORT then - debugger.missing[file] = true - DisplayOutputLn(TR("Couldn't activate file '%s' for debugging; continuing without it.") - :format(file)) - end - end - - return activated ~= nil -end - -local function reSetBreakpoints() - -- remove all breakpoints that may still be present from the last session - -- this only matters for those remote clients that reload scripts - -- without resetting their breakpoints - debugger.handle("delallb") - - -- go over all windows and find all breakpoints - if (not debugger.scratchpad) then - for _, document in pairs(ide.openDocuments) do - local editor = document.editor - local filePath = document.filePath - local line = editor:MarkerNext(0, BREAKPOINT_MARKER_VALUE) - while filePath and line ~= -1 do - debugger.handle("setb " .. filePath .. " " .. (line+1)) - line = editor:MarkerNext(line + 1, BREAKPOINT_MARKER_VALUE) - end - end - end -end - -debugger.shell = function(expression, isstatement) - -- check if the debugger is running and may be waiting for a response. - -- allow that request to finish, otherwise this function does nothing. - if debugger.running then debugger.update() end - if debugger.server and not debugger.running - and (not debugger.scratchpad or debugger.scratchpad.paused) then - copas.addthread(function () - -- exec command is not expected to return anything. - -- eval command returns 0 or more results. - -- 'values' has a list of serialized results returned. - -- as it is not possible to distinguish between 0 results and one - -- 'nil' value returned, 'nil' is always returned in this case. - -- the first value returned by eval command is not used; - -- this may need to be taken into account by other debuggers. - local addedret, forceexpression = true, expression:match("^%s*=%s*") - expression = expression:gsub("^%s*=%s*","") - local _, values, err = debugger.evaluate(expression) - if not forceexpression and err then - _, values, err = debugger.execute(expression) - addedret = false - end - - if err then - if addedret then err = err:gsub('^%[string "return ', '[string "') end - DisplayShellErr(err) - elseif addedret or #values > 0 then - if forceexpression then -- display elements as multi-line - for i,v in pairs(values) do -- stringify each of the returned values - local func = loadstring('return '..v) -- deserialize the value first - if func then -- if it's deserialized correctly - values[i] = (forceexpression and i > 1 and '\n' or '') .. - serialize(func(), {nocode = true, comment = 0, - -- if '=' is used, then use multi-line serialized output - indent = forceexpression and ' ' or nil}) - end - end - end - - -- if empty table is returned, then show nil if this was an expression - if #values == 0 and (forceexpression or not isstatement) then - values = {'nil'} - end - DisplayShell(unpack(values)) - end - - -- refresh Stack and Watch windows if executed a statement (and no err) - if isstatement and not err and not addedret and #values == 0 then - updateStackSync() updateWatchesSync() - end - end) - elseif debugger.server then - DisplayShellErr(TR("Can't evaluate the expression while the application is running.")) - end -end - -local function stoppedAtBreakpoint(file, line) - -- if this document can be activated and the current line has a breakpoint - local editor = activateDocument(file, line, activate.CHECKONLY) - if not editor then return false end - - local current = editor:MarkerNext(0, CURRENT_LINE_MARKER_VALUE) - local breakpoint = editor:MarkerNext(current, BREAKPOINT_MARKER_VALUE) - return breakpoint > -1 and breakpoint == current -end - -local function mapRemotePath(basedir, file, line, method) - if not file then return end - - -- file is /foo/bar/my.lua; basedir is d:\local\path\ - -- check for d:\local\path\my.lua, d:\local\path\bar\my.lua, ... - -- wxwidgets on Windows handles \\ and / as separators, but on OSX - -- and Linux it only handles 'native' separator; - -- need to translate for GetDirs to work. - local file = file:gsub("\\", "/") - local parts = wx.wxFileName(file):GetDirs() - local name = wx.wxFileName(file):GetFullName() - - -- find the longest remote path that can be mapped locally - local longestpath, remotedir - while true do - local mapped = GetFullPathIfExists(basedir, name) - if mapped then - longestpath = mapped - remotedir = file:gsub(q(name):gsub("/", ".").."$", "") - end - if #parts == 0 then break end - name = table.remove(parts, #parts) .. "/" .. name - end - - -- if found a local mapping under basedir - local activated = longestpath and activateDocument(longestpath, line, method or activate.NOREPORT) - if activated then - -- find remote basedir by removing the tail from remote file - debugger.handle("basedir " .. debugger.basedir .. "\t" .. remotedir) - -- reset breakpoints again as remote basedir has changed - reSetBreakpoints() - DisplayOutputLn(TR("Mapped remote request for '%s' to '%s'.") - :format(remotedir, debugger.basedir)) - - return longestpath - end - - return nil -end - -debugger.listen = function(start) - if start == false then - if debugger.listening then - debugger.terminate() -- terminate if running - copas.removeserver(debugger.listening) - DisplayOutputLn(TR("Debugger server stopped at %s:%d.") - :format(debugger.hostname, debugger.portnumber)) - debugger.listening = false - else - DisplayOutputLn(TR("Can't stop debugger server as it is not started.")) - end - return - end - - local server, err = socket.bind("*", debugger.portnumber) - if not server then - DisplayOutputLn(TR("Can't start debugger server at %s:%d: %s.") - :format(debugger.hostname, debugger.portnumber, err or TR("unknown error"))) - return - end - DisplayOutputLn(TR("Debugger server started at %s:%d.") - :format(debugger.hostname, debugger.portnumber)) - - copas.autoclose = false - copas.addserver(server, function (skt) - -- pull any pending data not processed yet - if debugger.running then debugger.update() end - if debugger.server then - DisplayOutputLn(TR("Refused a request to start a new debugging session as there is one in progress already.")) - return - end - - copas.setErrorHandler(function(error) - -- ignore errors that happen because debugging session is - -- terminated during handshake (server == nil in this case). - if debugger.server then - DisplayOutputLn(TR("Can't start debugging session due to internal error '%s'."):format(error)) - end - debugger.terminate() - end) - - local options = debugger.options or {} - -- this may be a remote call without using an interpreter and as such - -- debugger.options may not be set, but runonstart is still configured. - if not options.runstart then options.runstart = ide.config.debugger.runonstart end - - -- support allowediting as set in the interpreter or config - if not options.allowediting then options.allowediting = ide.config.debugger.allowediting end - - if not debugger.scratchpad and not options.allowediting then - SetAllEditorsReadOnly(true) - end - - debugger.server = copas.wrap(skt) - debugger.socket = skt - debugger.loop = false - debugger.scratchable = false - debugger.stats = {line = 0} - debugger.missing = {} - debugger.editormap = {} - debugger.runtocursor = nil - - local wxfilepath = GetEditorFileAndCurInfo() - local startfile = ide:GetProjectStartFile() or options.startwith - or (wxfilepath and wxfilepath:GetFullPath()) - - if not startfile then - DisplayOutputLn(TR("Can't start debugging without an opened file or with the current file not being saved ('%s').") - :format(ide.config.default.fullname)) - return debugger.terminate() - end - - local startpath = wx.wxFileName(startfile):GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR) - local basedir = options.basedir or FileTreeGetDir() or startpath - -- guarantee that the path has a trailing separator - debugger.basedir = wx.wxFileName.DirName(basedir):GetFullPath() - - -- load the remote file into the debugger - -- set basedir first, before loading to make sure that the path is correct - debugger.handle("basedir " .. debugger.basedir) - - local init = options.init or ide.config.debugger.init - if init then - local _, _, err = debugger.execute(init) - if err then DisplayOutputLn(TR("Ignored error in debugger initialization code: %s."):format(err)) end - end - - reSetBreakpoints() - - local redirect = ide.config.debugger.redirect or options.redirect - if redirect then - debugger.handle("output stdout " .. redirect, nil, - { handler = function(m) - -- if it's an error returned, then handle the error - if m and m:find("stack traceback:", 1, true) then - -- this is an error message sent remotely - local ok, res = LoadSafe("return "..m) - if ok then - DisplayOutputLn(res) - return - end - end - - if ide.config.debugger.outputfilter then - local ok, res = pcall(ide.config.debugger.outputfilter, m) - if ok then - m = res - else - DisplayOutputLn("Output filter failed: "..res) - return - end - elseif m then - local max = 240 - m = #m < max+4 and m or m:sub(1,max) .. "...\n" - end - if m then DisplayOutputNoMarker(m) end - end}) - end - - if (options.startwith) then - local file, line, err = debugger.loadfile(options.startwith) - if err then - DisplayOutputLn(TR("Can't run the entry point script ('%s').") - :format(options.startwith) - .." "..TR("Compilation error") - ..":\n"..err) - return debugger.terminate() - elseif options.runstart and not debugger.scratchpad then - if stoppedAtBreakpoint(file, line) then - activateDocument(file, line) - options.runstart = false - end - elseif file and line then - DisplayOutputLn(TR("Debugging suspended at '%s:%s' (couldn't activate the file).") - :format(file, line)) - end - elseif not (options.run or debugger.scratchpad) then - local file, line, err = debugger.loadfile(startfile) - -- "load" can work in two ways: (1) it can load the requested file - -- OR (2) it can "refuse" to load it if the client was started - -- with start() method, which can't load new files - -- if file and line are set, this indicates option #2 - if err then - DisplayOutputLn(TR("Can't start debugging for '%s'."):format(startfile) - .." "..TR("Compilation error") - ..":\n"..err) - return debugger.terminate() - elseif options.runstart then - local file = (mapRemotePath(basedir, file, line or 0, activate.CHECKONLY) - or file or startfile) - - if stoppedAtBreakpoint(file, line or 0) then - activateDocument(file, line or 0) - options.runstart = false - end - elseif file and line then - local activated = activateDocument(file, line, activate.NOREPORT) - - -- if not found, check using full file path and reset basedir - if not activated and not wx.wxIsAbsolutePath(file) then - activated = activateDocument(startpath..file, line, activate.NOREPORT) - if activated then - debugger.basedir = startpath - debugger.handle("basedir " .. debugger.basedir) - -- reset breakpoints again as basedir has changed - reSetBreakpoints() - end - end - - -- if not found and the files doesn't exist, it may be - -- a remote call; try to map it to the project folder. - -- also check for absolute path as it may need to be remapped - -- when autoactivation is disabled. - if not activated and (not wx.wxFileName(file):FileExists() - or wx.wxIsAbsolutePath(file)) then - if mapRemotePath(basedir, file, line, activate.NOREPORT) then - activated = true - end - end - - if not activated then - DisplayOutputLn(TR("Debugging suspended at '%s:%s' (couldn't activate the file).") - :format(file, line)) - end - - -- debugger may still be available for scratchpad, - -- if the interpreter signals scratchpad support, so enable it. - debugger.scratchable = ide.interpreter.scratchextloop ~= nil - else - debugger.scratchable = true - local activated = activateDocument(startfile, 0) -- find the appropriate line - if not activated then - DisplayOutputLn(TR("Debugging suspended at '%s:%s' (couldn't activate the file).") - :format(startfile, '?')) - end - end - end - - if (not options.noshell and not debugger.scratchpad) then - ShellSupportRemote(debugger.shell) - end - - debuggerToggleViews(true) - updateStackSync() - updateWatchesSync() - - DisplayOutputLn(TR("Debugging session started in '%s'."):format(debugger.basedir)) - - if (debugger.scratchpad) then - debugger.scratchpad.updated = true - else - if (options.runstart) then - ClearAllCurrentLineMarkers() - debugger.run() - end - if (options.run) then - local file, line = debugger.handle("run") - activateDocument(file, line) - end - end - - -- request attention if the debugging is stopped - if not debugger.running then RequestAttention() end - -- refresh toolbar and menus in case the main app is not active - ide:GetMainFrame():UpdateWindowUI(wx.wxUPDATE_UI_FROMIDLE) - ide:GetToolBar():UpdateWindowUI(wx.wxUPDATE_UI_FROMIDLE) - end) - debugger.listening = server -end - -local function nameOutputTab(name) - local nbk = ide.frame.bottomnotebook - local index = nbk:GetPageIndex(ide:GetOutput()) - if index ~= -1 then nbk:SetPageText(index, name) end -end - -debugger.handle = function(command, server, options) - local verbose = ide.config.debugger.verbose - local gprint = _G.print - _G.print = function (...) if verbose then DisplayOutputLn(...) end end - - nameOutputTab(TR("Output (running)")) - debugger.running = true - if verbose then DisplayOutputLn("Debugger sent (command):", command) end - local file, line, err = mobdebug.handle(command, server or debugger.server, options) - if verbose then DisplayOutputLn("Debugger received (file, line, err):", file, line, err) end - debugger.running = false - -- only set suspended if the debugging hasn't been terminated - if debugger.server then nameOutputTab(TR("Output (suspended)")) end - - _G.print = gprint - return file, line, err -end - -debugger.exec = function(command, func) - if debugger.server and not debugger.running then - copas.addthread(function () - -- execute a custom function (if any) in the context of this thread - if type(func) == 'function' then func() end - local out - local attempts = 0 - while true do - -- clear markers before running the command - -- don't clear if running trace as the marker is then invisible, - -- and it needs to be visible during tracing - if not debugger.loop then ClearAllCurrentLineMarkers() end - debugger.breaking = false - local file, line, err = debugger.handle(out or command) - if out then out = nil end - if line == nil then - if err then DisplayOutputLn(err) end - DebuggerStop() - return - elseif not debugger.server then - -- it is possible that while debugger.handle call was executing - -- the debugging was terminated; simply return in this case. - return - else - if activateDocument(file, line) then - debugger.stats.line = debugger.stats.line + 1 - if debugger.loop then - updateStackSync() - updateWatchesSync() - else - updateStackAndWatches() - return - end - else - -- clear the marker as it wasn't cleared earlier - if debugger.loop then ClearAllCurrentLineMarkers() end - -- we may be in some unknown location at this point; - -- If this happens, stop and report allowing users to set - -- breakpoints and step through. - if debugger.breaking then - DisplayOutputLn(TR("Debugging suspended at '%s:%s' (couldn't activate the file).") - :format(file, line)) - updateStackAndWatches() - return - end - -- redo now; if the call is from the debugger, then repeat - -- the same command, except when it was "run" (switch to 'step'); - -- this is needed to "break" execution that happens in on() call. - -- in all other cases get out of this file. - -- don't get out of "mobdebug", because it may happen with - -- start() or on() call, which will get us out of the current - -- file, which is not what we want. - -- Some engines (Corona SDK) report =?:0 as the current location. - -- repeat the same command, but check if this has been tried - -- too many times already; if so, get "out" - out = ((tonumber(line) == 0 and attempts < 10) and command - or (file:find('mobdebug%.lua$') - and (command == 'run' and 'step' or command) or "out")) - attempts = attempts + 1 - end - end - end - end) - end -end - -debugger.handleAsync = function(command) - if debugger.server and not debugger.running then - copas.addthread(function () debugger.handle(command) end) - end -end -debugger.handleDirect = function(command) - local sock = debugger.socket - if debugger.server and sock then - local running = debugger.running - -- this needs to be short as it will block the UI - sock:settimeout(0.25) - debugger.handle(command, sock) - sock:settimeout(0) - -- restore running status - debugger.running = running - end -end - -debugger.loadfile = function(file) - local f, l, err = debugger.handle("load " .. file) - if not f and wx.wxFileExists(file) and err and err:find("Cannot open file") then - local content = FileRead(file) - if content then return debugger.loadstring(file, content) end - end - return f, l, err -end -debugger.loadstring = function(file, string) - return debugger.handle("loadstring '" .. file .. "' " .. string) -end - -do - local nextupdatedelta = 0.250 - local nextupdate = TimeGet() + nextupdatedelta - local function forceUpdateOnWrap(editor) - -- http://www.scintilla.org/ScintillaDoc.html#LineWrapping - -- Scintilla doesn't perform wrapping immediately after a content change - -- for performance reasons, so the activation calculations can be wrong - -- if there is wrapping that pushes the current line out of the screen. - -- force editor update that performs wrapping recalculation. - if ide.config.editor.usewrap then editor:Update(); editor:Refresh() end - end - debugger.update = function() - if debugger.server or debugger.listening and TimeGet() > nextupdate then - copas.step(0) - nextupdate = TimeGet() + nextupdatedelta - end - - -- if there is any pending activation - if debugger.activate then - local file, line, content = unpack(debugger.activate) - debugger.activate = nil - if content then - local editor = NewFile() - editor:SetTextDyn(content) - if not ide.config.debugger.allowediting - and not (debugger.options or {}).allowediting then - editor:SetReadOnly(true) - end - forceUpdateOnWrap(editor) - activateDocument(file, line) - else - local editor = LoadFile(file) - if editor then - forceUpdateOnWrap(editor) - activateDocument(file, line) - end - end - end - end -end - -local function isemptyline(editor, line) - local text = editor:GetLineDyn(line-1) - return not text:find("%S") - or (text:find("^%s*%-%-") ~= nil and text:find("^%s*%-%-%[=*%[") == nil) -end - -debugger.terminate = function() - if debugger.server then - if debugger.pid then -- if there is PID, try local kill - killClient() - else -- otherwise, try graceful exit for the remote process - debugger.breaknow("exit") - end - DebuggerStop() - end -end -debugger.step = function() debugger.exec("step") end -debugger.trace = function() - debugger.loop = true - debugger.exec("step") -end -debugger.runto = function(editor, line) - -- check if the location is valid for a breakpoint - if isemptyline(editor, line+1) then return end - - local ed, ln = unpack(debugger.runtocursor or {}) - local same = ed and ln and ed:GetId() == editor:GetId() and ln == line - - -- check if there is already a breakpoint in the "run to" location; - -- if so, don't mark the location as "run to" as it will stop there anyway - if bit.band(editor:MarkerGet(line), BREAKPOINT_MARKER_VALUE) > 0 - and not same then - debugger.runtocursor = nil - debugger.run() - return - end - - -- save the location of the breakpoint - debugger.runtocursor = {editor, line} - -- set breakpoint and execute run - debugger.exec("run", function() - -- if run-to-cursor location is already set, then remove the breakpoint, - -- but only if this location is different - if ed and ln and not same then - DebuggerToggleBreakpoint(ed, ln) - debugger.wait() - end - if not same then - DebuggerToggleBreakpoint(editor, line) - debugger.wait() - end - end) -end -debugger.wait = function() - -- wait for all results to come back - while debugger.running do debugger.update() end -end -debugger.over = function() debugger.exec("over") end -debugger.out = function() debugger.exec("out") end -debugger.run = function() debugger.exec("run") end -debugger.detach = function() - if debugger.running then - debugger.handleDirect("done") - debugger.server = nil - else - debugger.exec("done") - end -end -debugger.evaluate = function(expression) return debugger.handle('eval ' .. expression) end -debugger.execute = function(expression) return debugger.handle('exec ' .. expression) end -debugger.stack = function() return debugger.handle('stack') end -debugger.breaknow = function(command) - -- stop if we're running a "trace" command - debugger.loop = false - - -- force suspend command; don't use copas interface as it checks - -- for the other side "reading" and the other side is not reading anything. - -- use the "original" socket to send "suspend" command. - -- this will only break on the next Lua command. - if debugger.socket then - local running = debugger.running - -- this needs to be short as it will block the UI - debugger.socket:settimeout(0.25) - local file, line, err = debugger.handle(command or "suspend", debugger.socket) - debugger.socket:settimeout(0) - -- restore running status - debugger.running = running - debugger.breaking = true - -- don't need to do anything else as the earlier call (run, step, etc.) - -- will get the results (file, line) back and will update the UI - return file, line, err - end -end -debugger.breakpoint = function(file, line, state) - if debugger.running then - return debugger.handleDirect((state and "asetb " or "adelb ") .. file .. " " .. line) - end - return debugger.handleAsync((state and "setb " or "delb ") .. file .. " " .. line) -end -debugger.quickeval = function(var, callback) - if debugger.server and not debugger.running - and not debugger.scratchpad and not (debugger.options or {}).noeval then - copas.addthread(function () - local _, values, err = debugger.evaluate(var) - local val = err - and err:gsub("%[.-%]:%d+:%s*","error: ") - or (var .. " = " .. (#values > 0 and values[1] or 'nil')) - if callback then callback(val) end - end) - end -end - -local width, height = 360, 200 - -local keyword = {} -for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', - 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', - 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end - -local function stringifyKeyIntoPrefix(name, num) - return (type(name) == "number" - and (num and num == name and '' or ("[%s] = "):format(name)) - or type(name) == "string" and (name:match("^[%l%u_][%w_]*$") and not keyword[name] - and ("%s = "):format(name) - or ("[%q] = "):format(name)) - or ("[%s] = "):format(tostring(name))) -end - -local function debuggerCreateStackWindow() - local stackCtrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(width, height), - wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE - + wx.wxTR_HIDE_ROOT + wx.wxNO_BORDER) - - debugger.stackCtrl = stackCtrl - - stackCtrl:SetImageList(debugger.imglist) - - local valuecache = {} - function stackCtrl:SetItemValueIfExpandable(item, value) - local expandable = type(value) == 'table' and next(value) ~= nil - if expandable then -- cache table value to expand when requested - valuecache[item:GetValue()] = value - end - self:SetItemHasChildren(item, expandable) - end - - function stackCtrl:DeleteAll() - self:DeleteAllItems() - valuecache = {} - end - - function stackCtrl:GetItemChildren(item) - return valuecache[item:GetValue()] or {} - end - - stackCtrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING, - function (event) - local item_id = event:GetItem() - local count = stackCtrl:GetChildrenCount(item_id, false) - if count > 0 then return true end - - local image = stackCtrl:GetItemImage(item_id) - local num = 1 - for name,value in pairs(stackCtrl:GetItemChildren(item_id)) do - local strval = fixUTF8(trimToMaxLength(serialize(value, params))) - local text = stringifyKeyIntoPrefix(name, num)..strval - local item = stackCtrl:AppendItem(item_id, text, image) - stackCtrl:SetItemValueIfExpandable(item, value) - - num = num + 1 - if num > stackmaxnum then break end - end - return true - end) - - stackCtrl:Connect(wx.wxEVT_SET_FOCUS, function(event) - if debugger.needrefresh.stack then - updateStack() - debugger.needrefresh.stack = false - end - end) - - -- register navigation callback - stackCtrl:Connect(wx.wxEVT_LEFT_DCLICK, function (event) - local item_id = stackCtrl:HitTest(event:GetPosition()) - if not item_id or not item_id:IsOk() then event:Skip() return end - - local coords = callData[item_id:GetValue()] - if not coords then event:Skip() return end - - local file, line = coords[1], coords[2] - if file:match("@") then file = string.sub(file, 2) end - file = GetFullPathIfExists(debugger.basedir, file) - if file then - local editor = LoadFile(file,nil,true) - editor:SetFocus() - if line then editor:GotoLine(line-1) end - end - end) - - local layout = ide:GetSetting("/view", "uimgrlayout") - if layout and not layout:find("stackpanel") then - ide:AddPanelDocked(ide.frame.bottomnotebook, stackCtrl, "stackpanel", TR("Stack")) - else - ide:AddPanel(stackCtrl, "stackpanel", TR("Stack")) - end -end - -local function debuggerCreateWatchWindow() - local watchCtrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(width, height), - wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE - + wx.wxTR_HIDE_ROOT + wx.wxTR_EDIT_LABELS + wx.wxNO_BORDER) - - debugger.watchCtrl = watchCtrl - - local root = watchCtrl:AddRoot("Watch") - watchCtrl:SetImageList(debugger.imglist) - - local defaultExpr = "watch expression" - local expressions = {} -- table to keep track of expressions - - function watchCtrl:SetItemExpression(item, expr, value) - expressions[item:GetValue()] = expr - self:SetItemText(item, expr .. ' = ' .. (value or '?')) - self:SelectItem(item, true) - if not value then updateWatches(item) end - end - - function watchCtrl:GetItemExpression(item) - return expressions[item:GetValue()] - end - - local names = {} - function watchCtrl:SetItemName(item, name) - local nametype = type(name) - names[item:GetValue()] = ( - (nametype == 'string' or nametype == 'number' or nametype == 'boolean') - and name or nil - ) - end - - function watchCtrl:GetItemName(item) - return names[item:GetValue()] - end - - local valuecache = {} - function watchCtrl:SetItemValueIfExpandable(item, value) - local expandable = type(value) == 'table' and next(value) ~= nil - valuecache[item:GetValue()] = expandable and value or nil - self:SetItemHasChildren(item, expandable) - end - - function watchCtrl:GetItemChildren(item) - return valuecache[item:GetValue()] or {} - end - - function watchCtrl:IsWatch(item) - return item:IsOk() and watchCtrl:GetItemParent(item):GetValue() == root:GetValue() - end - - function watchCtrl:IsEditable(item) - return (item and item:IsOk() - and (watchCtrl:IsWatch(item) or watchCtrl:GetItemName(item) ~= nil)) - end - - function watchCtrl:GetItemFullExpression(item) - local expr = '' - while true do - local name = watchCtrl:GetItemName(item) - expr = (watchCtrl:IsWatch(item) - and ('({%s})[1]'):format(watchCtrl:GetItemExpression(item)) - or (type(name) == 'string' and '[%q]' or '[%s]'):format(tostring(name)) - )..expr - if watchCtrl:IsWatch(item) then break end - item = watchCtrl:GetItemParent(item) - if not item:IsOk() then break end - end - return expr, item:IsOk() and item or nil - end - - function watchCtrl:CopyItemValue(item) - local expr = self:GetItemFullExpression(item) - - if debugger.running then debugger.update() end - if debugger.server and not debugger.running - and (not debugger.scratchpad or debugger.scratchpad.paused) then - copas.addthread(function () - local _, values, error = debugger.evaluate(expr) - ide:CopyToClipboard(error and error:gsub("%[.-%]:%d+:%s+","") - or (#values == 0 and 'nil' or values[1])) - end) - end - end - - function watchCtrl:UpdateItemValue(item, value) - local expr, itemupd = self:GetItemFullExpression(item) - - if debugger.running then debugger.update() end - if debugger.server and not debugger.running - and (not debugger.scratchpad or debugger.scratchpad.paused) then - copas.addthread(function () - local _, _, err = debugger.execute(expr..'='..value) - if err then - watchCtrl:SetItemText(item, 'error: '..err:gsub("%[.-%]:%d+:%s+","")) - elseif itemupd then - updateWatchesSync(itemupd) - end - updateStackSync() - end) - end - end - - watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING, - function (event) - local item_id = event:GetItem() - local count = watchCtrl:GetChildrenCount(item_id, false) - if count > 0 then return true end - - local image = watchCtrl:GetItemImage(item_id) - local num = 1 - for name,value in pairs(watchCtrl:GetItemChildren(item_id)) do - local strval = fixUTF8(trimToMaxLength(serialize(value, params))) - local text = stringifyKeyIntoPrefix(name, num)..strval - local item = watchCtrl:AppendItem(item_id, text, image) - watchCtrl:SetItemValueIfExpandable(item, value) - watchCtrl:SetItemName(item, name) - - num = num + 1 - if num > stackmaxnum then break end - end - return true - end) - - watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_DELETE_ITEM, - function (event) - local value = event:GetItem():GetValue() - expressions[value] = nil - valuecache[value] = nil - names[value] = nil - end) - - watchCtrl:Connect(wx.wxEVT_SET_FOCUS, function(event) - if debugger.needrefresh.watches then - updateWatches() - debugger.needrefresh.watches = false - end - end) - - - local item - -- wx.wxEVT_CONTEXT_MENU is only triggered over tree items on OSX, - -- but it needs to be also triggered below any item to add a watch, - -- so use RIGHT_DOWN instead - watchCtrl:Connect(wx.wxEVT_RIGHT_DOWN, - function (event) - -- store the item to be used in edit/delete actions - item = watchCtrl:HitTest(watchCtrl:ScreenToClient(wx.wxGetMousePosition())) - local editlabel = watchCtrl:IsWatch(item) and TR("&Edit Watch") or TR("&Edit Value") - local menu = wx.wxMenu { - { ID_ADDWATCH, TR("&Add Watch")..KSC(ID_ADDWATCH) }, - { ID_EDITWATCH, editlabel..KSC(ID_EDITWATCH) }, - { ID_DELETEWATCH, TR("&Delete Watch")..KSC(ID_DELETEWATCH) }, - { ID_COPYWATCHVALUE, TR("&Copy Value")..KSC(ID_COPYWATCHVALUE) }, - } - PackageEventHandle("onMenuWatch", menu, watchCtrl, event) - watchCtrl:PopupMenu(menu) - item = nil - end) - - watchCtrl:Connect(ID_ADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) watchCtrl:EditLabel(watchCtrl:AppendItem(root, defaultExpr, image.LOCAL)) end) - - watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) watchCtrl:EditLabel(item or watchCtrl:GetSelection()) end) - watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(watchCtrl:IsEditable(item or watchCtrl:GetSelection())) end) - - watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) watchCtrl:Delete(item or watchCtrl:GetSelection()) end) - watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(watchCtrl:IsWatch(item or watchCtrl:GetSelection())) end) - - watchCtrl:Connect(ID_COPYWATCHVALUE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) watchCtrl:CopyItemValue(item or watchCtrl:GetSelection()) end) - watchCtrl:Connect(ID_COPYWATCHVALUE, wx.wxEVT_UPDATE_UI, function (event) - -- allow copying only when the debugger is available - event:Enable(item:IsOk() and debugger.server and not debugger.running - and (not debugger.scratchpad or debugger.scratchpad.paused)) - end) - - local label - watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, - function (event) - local item = event:GetItem() - if not (item:IsOk() and watchCtrl:IsEditable(item)) then - event:Veto() - return - end - - label = watchCtrl:GetItemText(item) - - if watchCtrl:IsWatch(item) then - local expr = watchCtrl:GetItemExpression(item) - if expr then watchCtrl:SetItemText(item, expr) end - else - local prefix = stringifyKeyIntoPrefix(watchCtrl:GetItemName(item)) - local val = watchCtrl:GetItemText(item):gsub(q(prefix),'') - watchCtrl:SetItemText(item, val) - end - end) - watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT, - function (event) - event:Veto() - - local item = event:GetItem() - if event:IsEditCancelled() then - if watchCtrl:GetItemText(item) == defaultExpr then - -- when Delete is called from END_EDIT, it causes infinite loop - -- on OSX (wxwidgets 2.9.5) as Delete calls END_EDIT again. - -- disable handlers during Delete and then enable back. - watchCtrl:SetEvtHandlerEnabled(false) - watchCtrl:Delete(item) - watchCtrl:SetEvtHandlerEnabled(true) - else - watchCtrl:SetItemText(item, label) - end - else - if watchCtrl:IsWatch(item) then - watchCtrl:SetItemExpression(item, event:GetLabel()) - else - watchCtrl:UpdateItemValue(item, event:GetLabel()) - end - end - event:Skip() - end) - - local layout = ide:GetSetting("/view", "uimgrlayout") - if layout and not layout:find("watchpanel") then - ide:AddPanelDocked(ide.frame.bottomnotebook, watchCtrl, "watchpanel", TR("Watch")) - else - ide:AddPanel(watchCtrl, "watchpanel", TR("Watch")) - end -end - -debuggerCreateStackWindow() -debuggerCreateWatchWindow() - ----------------------------------------------- --- public api - -DebuggerRefreshPanels = updateStackAndWatches - -function DebuggerAttachDefault(options) - debugger.options = options - if (debugger.listening) then return end - debugger.listen() -end - -function DebuggerShutdown() - if debugger.server then debugger.terminate() end - if debugger.pid then killClient() end -end - -function DebuggerStop(resetpid) - if (debugger.server) then - debugger.server = nil - SetAllEditorsReadOnly(false) - ShellSupportRemote(nil) - ClearAllCurrentLineMarkers() - DebuggerScratchpadOff() - debuggerToggleViews(false) - local lines = TR("traced %d instruction", debugger.stats.line):format(debugger.stats.line) - DisplayOutputLn(TR("Debugging session completed (%s)."):format(lines)) - nameOutputTab(debugger.pid and TR("Output (running)") or TR("Output")) - if debugger.runtocursor then - local ed, ln = unpack(debugger.runtocursor) - DebuggerToggleBreakpoint(ed, ln) - end - else - -- it's possible that the application couldn't start, or that the - -- debugger in the application didn't start, which means there is - -- no debugger.server, but scratchpad may still be on. Turn it off. - DebuggerScratchpadOff() - end - -- reset pid for "running" (not debugged) processes - if resetpid then debugger.pid = nil end -end - -local function debuggerMakeFileName(editor) - return ide:GetDocument(editor):GetFilePath() - or ide:GetDocument(editor):GetFileName() - or ide.config.default.fullname -end - -function DebuggerToggleBreakpoint(editor, line, value) - local isset = bit.band(editor:MarkerGet(line), BREAKPOINT_MARKER_VALUE) > 0 - if value ~= nil and isset == value then return end - local filePath = debugger.editormap and debugger.editormap[editor] - or debuggerMakeFileName(editor) - if isset then - -- if there is pending "run-to-cursor" call at this location, remove it - local ed, ln = unpack(debugger.runtocursor or {}) - local same = ed and ln and ed:GetId() == editor:GetId() and ln == line - if same then debugger.runtocursor = nil end - - editor:MarkerDelete(line, BREAKPOINT_MARKER) - if debugger.server then debugger.breakpoint(filePath, line+1, false) end - else - if isemptyline(editor, line+1) then return end - - editor:MarkerAdd(line, BREAKPOINT_MARKER) - if debugger.server then debugger.breakpoint(filePath, line+1, true) end - end - PackageEventHandle("onEditorMarkerUpdate", editor, BREAKPOINT_MARKER, line+1, not isset) -end - --- scratchpad functions - -function DebuggerRefreshScratchpad() - if debugger.scratchpad and debugger.scratchpad.updated and not debugger.scratchpad.paused then - - local scratchpadEditor = debugger.scratchpad.editor - if scratchpadEditor.spec.apitype - and scratchpadEditor.spec.apitype == "lua" - and not ide.interpreter.skipcompile - and not CompileProgram(scratchpadEditor, { jumponerror = false, reportstats = false }) - then return end - - local code = StripShebang(scratchpadEditor:GetTextDyn()) - if debugger.scratchpad.running then - -- break the current execution first - -- don't try too frequently to avoid overwhelming the debugger - local now = TimeGet() - if now - debugger.scratchpad.running > 0.250 then - debugger.breaknow() - debugger.scratchpad.running = now - end - else - local clear = ide:GetMenuBar():IsChecked(ID_CLEAROUTPUT) - local filePath = debuggerMakeFileName(scratchpadEditor) - - -- wrap into a function call to make "return" to work with scratchpad - code = "(function()"..code.."\nend)()" - - -- this is a special error message that is generated at the very end - -- of each script to avoid exiting the (debugee) scratchpad process. - -- these errors are handled and not reported to the user - local errormsg = 'execution suspended at ' .. TimeGet() - local stopper = "error('" .. errormsg .. "')" - -- store if interpreter requires a special handling for external loop - local extloop = ide.interpreter.scratchextloop - - local function reloadScratchpadCode() - debugger.scratchpad.running = TimeGet() - debugger.scratchpad.updated = false - debugger.scratchpad.runs = (debugger.scratchpad.runs or 0) + 1 - - if clear then ClearOutput(true) end - - -- the code can be running in two ways under scratchpad: - -- 1. controlled by the application, requires stopper (most apps) - -- 2. controlled by some external loop (for example, love2d). - -- in the first case we need to reload the app after each change - -- in the second case, we need to load the app once and then - -- "execute" new code to reflect the changes (with some limitations). - local _, _, err - if extloop then -- if the execution is controlled by an external loop - if debugger.scratchpad.runs == 1 - then _, _, err = debugger.loadstring(filePath, code) - else _, _, err = debugger.execute(code) end - else _, _, err = debugger.loadstring(filePath, code .. stopper) end - - -- when execute() is used, it's not possible to distinguish between - -- compilation and run-time error, so just report as "Scratchpad error" - local prefix = extloop and TR("Scratchpad error") or TR("Compilation error") - - if not err then - _, _, err = debugger.handle("run") - prefix = TR("Execution error") - end - if err and not err:find(errormsg) then - local fragment, line = err:match('.-%[string "([^\010\013]+)"%]:(%d+)%s*:') - -- make the code shorter to better see the error message - if prefix == TR("Scratchpad error") and fragment and #fragment > 30 then - err = err:gsub(q(fragment), function(s) return s:sub(1,30)..'...' end) - end - DisplayOutputLn(prefix - ..(line and (" "..TR("on line %d"):format(line)) or "") - ..":\n"..err:gsub('stack traceback:.+', ''):gsub('\n+$', '')) - end - debugger.scratchpad.running = false - end - - copas.addthread(reloadScratchpadCode) - end - end -end - -local numberStyle = wxstc.wxSTC_LUA_NUMBER - -function DebuggerScratchpadOn(editor) - -- first check if there is already scratchpad editor. - -- this may happen when more than one editor is being added... - - if debugger.scratchpad and debugger.scratchpad.editors then - debugger.scratchpad.editors[editor] = true - else - debugger.scratchpad = {editor = editor, editors = {[editor] = true}} - - -- check if the debugger is already running; this happens when - -- scratchpad is turned on after external script has connected - if debugger.server then - debugger.scratchpad.updated = true - ClearAllCurrentLineMarkers() - SetAllEditorsReadOnly(false) - ShellSupportRemote(nil) -- disable remote shell - DebuggerRefreshScratchpad() - elseif not ProjectDebug(true, "scratchpad") then - debugger.scratchpad = nil - return - end - end - - local scratchpadEditor = editor - scratchpadEditor:StyleSetUnderline(numberStyle, true) - debugger.scratchpad.margin = scratchpadEditor:GetMarginWidth(0) + - scratchpadEditor:GetMarginWidth(1) + scratchpadEditor:GetMarginWidth(2) - - scratchpadEditor:Connect(wxstc.wxEVT_STC_MODIFIED, function(event) - local evtype = event:GetModificationType() - if (bit.band(evtype,wxstc.wxSTC_MOD_INSERTTEXT) ~= 0 or - bit.band(evtype,wxstc.wxSTC_MOD_DELETETEXT) ~= 0 or - bit.band(evtype,wxstc.wxSTC_PERFORMED_UNDO) ~= 0 or - bit.band(evtype,wxstc.wxSTC_PERFORMED_REDO) ~= 0) then - debugger.scratchpad.updated = true - debugger.scratchpad.editor = scratchpadEditor - end - event:Skip() - end) - - scratchpadEditor:Connect(wx.wxEVT_LEFT_DOWN, function(event) - local scratchpad = debugger.scratchpad - - local point = event:GetPosition() - local pos = scratchpadEditor:PositionFromPoint(point) - - -- are we over a number in the scratchpad? if not, it's not our event - if ((not scratchpad) or - (bit.band(scratchpadEditor:GetStyleAt(pos),31) ~= numberStyle)) then - event:Skip() - return - end - - -- find start position and length of the number - local text = scratchpadEditor:GetTextDyn() - - local nstart = pos - while nstart >= 0 - and (bit.band(scratchpadEditor:GetStyleAt(nstart),31) == numberStyle) - do nstart = nstart - 1 end - - local nend = pos - while nend < string.len(text) - and (bit.band(scratchpadEditor:GetStyleAt(nend),31) == numberStyle) - do nend = nend + 1 end - - -- check if there is minus sign right before the number and include it - if nstart >= 0 and scratchpadEditor:GetTextRangeDyn(nstart,nstart+1) == '-' then - nstart = nstart - 1 - end - scratchpad.start = nstart + 1 - scratchpad.length = nend - nstart - 1 - scratchpad.origin = scratchpadEditor:GetTextRangeDyn(nstart+1,nend) - if tonumber(scratchpad.origin) then - scratchpad.point = point - scratchpadEditor:BeginUndoAction() - scratchpadEditor:CaptureMouse() - end - end) - - scratchpadEditor:Connect(wx.wxEVT_LEFT_UP, function(event) - if debugger.scratchpad and debugger.scratchpad.point then - debugger.scratchpad.point = nil - scratchpadEditor:EndUndoAction() - scratchpadEditor:ReleaseMouse() - wx.wxSetCursor(wx.wxNullCursor) -- restore cursor - else event:Skip() end - end) - - scratchpadEditor:Connect(wx.wxEVT_MOTION, function(event) - local point = event:GetPosition() - local pos = scratchpadEditor:PositionFromPoint(point) - local scratchpad = debugger.scratchpad - local ipoint = scratchpad and scratchpad.point - - -- record the fact that we are over a number or dragging slider - scratchpad.over = scratchpad and - (ipoint ~= nil or (bit.band(scratchpadEditor:GetStyleAt(pos),31) == numberStyle)) - - if ipoint then - local startpos = scratchpad.start - local endpos = scratchpad.start+scratchpad.length - - -- calculate difference in point position - local dx = point.x - ipoint.x - - -- calculate the number of decimal digits after the decimal point - local origin = scratchpad.origin - local decdigits = #(origin:match('%.(%d+)') or '') - - -- calculate new value - local value = tonumber(origin) + dx * 10^-decdigits - - -- convert new value back to string to check the number of decimal points - -- this is needed because the rate of change is determined by the - -- current value. For example, for number 1, the next value is 2, - -- but for number 1.1, the next is 1.2 and for 1.01 it is 1.02. - -- But if 1.01 becomes 1.00, the both zeros after the decimal point - -- need to be preserved to keep the increment ratio the same when - -- the user wants to release the slider and start again. - origin = tostring(value) - local newdigits = #(origin:match('%.(%d+)') or '') - if decdigits ~= newdigits then - origin = origin .. (origin:find('%.') and '' or '.') .. ("0"):rep(decdigits-newdigits) - end - - -- update length - scratchpad.length = #origin - - -- update the value in the document - scratchpadEditor:SetTargetStart(startpos) - scratchpadEditor:SetTargetEnd(endpos) - scratchpadEditor:ReplaceTarget(origin) - else event:Skip() end - end) - - scratchpadEditor:Connect(wx.wxEVT_SET_CURSOR, function(event) - if (debugger.scratchpad and debugger.scratchpad.over) then - event:SetCursor(wx.wxCursor(wx.wxCURSOR_SIZEWE)) - elseif debugger.scratchpad and ide.osname == 'Unix' then - -- restore the cursor manually on Linux since event:Skip() doesn't reset it - local ibeam = event:GetX() > debugger.scratchpad.margin - event:SetCursor(wx.wxCursor(ibeam and wx.wxCURSOR_IBEAM or wx.wxCURSOR_RIGHT_ARROW)) - else event:Skip() end - end) - - return true -end - -function DebuggerScratchpadOff() - if not debugger.scratchpad then return end - - for scratchpadEditor in pairs(debugger.scratchpad.editors) do - scratchpadEditor:StyleSetUnderline(numberStyle, false) - scratchpadEditor:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wxstc.wxEVT_STC_MODIFIED) - scratchpadEditor:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_MOTION) - scratchpadEditor:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_LEFT_DOWN) - scratchpadEditor:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_LEFT_UP) - scratchpadEditor:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_SET_CURSOR) - end - - wx.wxSetCursor(wx.wxNullCursor) -- restore cursor - - debugger.scratchpad = nil - debugger.terminate() - - -- disable menu if it is still enabled - -- (as this may be called when the debugger is being shut down) - local menuBar = ide.frame.menuBar - if menuBar:IsChecked(ID_RUNNOW) then menuBar:Check(ID_RUNNOW, false) end - - return true -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/editor.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/editor.lua deleted file mode 100644 index 3b42c23..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/editor.lua +++ /dev/null @@ -1,1619 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local editorID = 100 -- window id to create editor pages with, incremented for new editors - -local openDocuments = ide.openDocuments -local notebook = ide.frame.notebook -local edcfg = ide.config.editor -local styles = ide.config.styles -local unpack = table.unpack or unpack -local q = EscapeMagic - -local margin = { LINENUMBER = 0, MARKER = 1, FOLD = 2 } -local linenumlen = 4 + 0.5 -local foldtypes = { - [0] = { wxstc.wxSTC_MARKNUM_FOLDEROPEN, wxstc.wxSTC_MARKNUM_FOLDER, - wxstc.wxSTC_MARKNUM_FOLDERSUB, wxstc.wxSTC_MARKNUM_FOLDERTAIL, wxstc.wxSTC_MARKNUM_FOLDEREND, - wxstc.wxSTC_MARKNUM_FOLDEROPENMID, wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, - }, - box = { wxstc.wxSTC_MARK_BOXMINUS, wxstc.wxSTC_MARK_BOXPLUS, - wxstc.wxSTC_MARK_VLINE, wxstc.wxSTC_MARK_LCORNER, wxstc.wxSTC_MARK_BOXPLUSCONNECTED, - wxstc.wxSTC_MARK_BOXMINUSCONNECTED, wxstc.wxSTC_MARK_TCORNER, - }, - circle = { wxstc.wxSTC_MARK_CIRCLEMINUS, wxstc.wxSTC_MARK_CIRCLEPLUS, - wxstc.wxSTC_MARK_VLINE, wxstc.wxSTC_MARK_LCORNERCURVE, wxstc.wxSTC_MARK_CIRCLEPLUSCONNECTED, - wxstc.wxSTC_MARK_CIRCLEMINUSCONNECTED, wxstc.wxSTC_MARK_TCORNERCURVE, - }, - plus = { wxstc.wxSTC_MARK_MINUS, wxstc.wxSTC_MARK_PLUS }, - arrow = { wxstc.wxSTC_MARK_ARROWDOWN, wxstc.wxSTC_MARK_ARROW }, -} - --- ---------------------------------------------------------------------------- --- Update the statusbar text of the frame using the given editor. --- Only update if the text has changed. -local statusTextTable = { "OVR?", "R/O?", "Cursor Pos" } - -local function updateStatusText(editor) - local texts = { "", "", "" } - if ide.frame and editor then - local pos = editor:GetCurrentPos() - local selected = #editor:GetSelectedText() - local selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1 - - texts = { - iff(editor:GetOvertype(), TR("OVR"), TR("INS")), - iff(editor:GetReadOnly(), TR("R/O"), TR("R/W")), - table.concat({ - TR("Ln: %d"):format(editor:LineFromPosition(pos) + 1), - TR("Col: %d"):format(editor:GetColumn(pos) + 1), - selected > 0 and TR("Sel: %d/%d"):format(selected, selections) or "", - }, ' ')} - end - - if ide.frame then - for n in ipairs(texts) do - if (texts[n] ~= statusTextTable[n]) then - ide:SetStatus(texts[n], n) - statusTextTable[n] = texts[n] - end - end - end -end - -local function updateBraceMatch(editor) - local pos = editor:GetCurrentPos() - local posp = pos > 0 and pos-1 - local char = editor:GetCharAt(pos) - local charp = posp and editor:GetCharAt(posp) - local match = { [string.byte("<")] = true, - [string.byte(">")] = true, - [string.byte("(")] = true, - [string.byte(")")] = true, - [string.byte("{")] = true, - [string.byte("}")] = true, - [string.byte("[")] = true, - [string.byte("]")] = true, - } - - pos = (match[char] and pos) or (charp and match[charp] and posp) - - if (pos) then - -- don't match brackets in markup comments - local style = bit.band(editor:GetStyleAt(pos), 31) - if (MarkupIsSpecial and MarkupIsSpecial(style) - or editor.spec.iscomment[style]) then return end - - local pos2 = editor:BraceMatch(pos) - if (pos2 == wxstc.wxSTC_INVALID_POSITION) then - editor:BraceBadLight(pos) - else - editor:BraceHighlight(pos,pos2) - end - editor.matchon = true - elseif(editor.matchon) then - editor:BraceBadLight(wxstc.wxSTC_INVALID_POSITION) - editor:BraceHighlight(wxstc.wxSTC_INVALID_POSITION,-1) - editor.matchon = false - end -end - --- Check if file is altered, show dialog to reload it -local function isFileAlteredOnDisk(editor) - if not editor then return end - - local id = editor:GetId() - if openDocuments[id] then - local filePath = openDocuments[id].filePath - local fileName = openDocuments[id].fileName - local oldModTime = openDocuments[id].modTime - - if filePath and (string.len(filePath) > 0) and oldModTime and oldModTime:IsValid() then - local modTime = GetFileModTime(filePath) - if modTime == nil then - openDocuments[id].modTime = nil - wx.wxMessageBox( - TR("File '%s' no longer exists."):format(fileName), - GetIDEString("editormessage"), - wx.wxOK + wx.wxCENTRE, ide.frame) - elseif not editor:GetReadOnly() and modTime:IsValid() and oldModTime:IsEarlierThan(modTime) then - local ret = (edcfg.autoreload and (not ide:GetDocument(editor):IsModified()) and wx.wxYES) - or wx.wxMessageBox( - TR("File '%s' has been modified on disk."):format(fileName) - .."\n"..TR("Do you want to reload it?"), - GetIDEString("editormessage"), - wx.wxYES_NO + wx.wxCENTRE, ide.frame) - - if ret ~= wx.wxYES or ReLoadFile(filePath, editor, true) then - openDocuments[id].modTime = GetFileModTime(filePath) - end - end - end - end -end - -local function navigateToPosition(editor, fromPosition, toPosition, length) - table.insert(editor.jumpstack, fromPosition) - editor:GotoPosEnforcePolicy(toPosition) - if length then - editor:SetAnchor(toPosition + length) - end -end - -local function navigateBack(editor) - if #editor.jumpstack == 0 then return end - local pos = table.remove(editor.jumpstack) - editor:GotoPosEnforcePolicy(pos) - return true -end - --- ---------------------------------------------------------------------------- --- Get/Set notebook editor page, use nil for current page, returns nil if none -function GetEditor(selection) - if selection == nil then - selection = notebook:GetSelection() - end - local editor - if (selection >= 0) and (selection < notebook:GetPageCount()) - and (notebook:GetPage(selection):GetClassInfo():GetClassName()=="wxStyledTextCtrl") then - editor = notebook:GetPage(selection):DynamicCast("wxStyledTextCtrl") - end - return editor -end - --- init new notebook page selection, use nil for current page -function SetEditorSelection(selection) - local editor = GetEditor(selection) - updateStatusText(editor) -- update even if nil - ide.frame:SetTitle(ExpandPlaceholders(ide.config.format.apptitle)) - - if editor then - editor:SetFocus() - editor:SetSTCFocus(true) - - local id = editor:GetId() - FileTreeMarkSelected(openDocuments[id] and openDocuments[id].filePath or '') - AddToFileHistory(openDocuments[id] and openDocuments[id].filePath) - else - FileTreeMarkSelected('') - end - - SetAutoRecoveryMark() -end - -function GetEditorFileAndCurInfo(nochecksave) - local editor = GetEditor() - if (not (editor and (nochecksave or SaveIfModified(editor)))) then - return - end - - local id = editor:GetId() - local filepath = openDocuments[id].filePath - if not filepath then return end - - local fn = wx.wxFileName(filepath) - fn:Normalize() - - local info = {} - info.pos = editor:GetCurrentPos() - info.line = editor:GetCurrentLine() - info.sel = editor:GetSelectedText() - info.sel = info.sel and info.sel:len() > 0 and info.sel or nil - info.selword = info.sel and info.sel:match("([^a-zA-Z_0-9]+)") or info.sel - - return fn,info -end - -function EditorAutoComplete(editor) - if not (editor and editor.spec) then return end - - local pos = editor:GetCurrentPos() - -- don't do auto-complete in comments or strings. - -- the current position and the previous one have default style (0), - -- so we need to check two positions back. - local style = pos >= 2 and bit.band(editor:GetStyleAt(pos-2),31) or 0 - if editor.spec.iscomment[style] or editor.spec.isstring[style] then return end - - -- retrieve the current line and get a string to the current cursor position in the line - local line = editor:GetCurrentLine() - local linetx = editor:GetLineDyn(line) - local linestart = editor:PositionFromLine(line) - local localpos = pos-linestart - - local lt = linetx:sub(1,localpos) - lt = lt:gsub("%s*(["..editor.spec.sep.."])%s*", "%1") - -- strip closed brace scopes - lt = lt:gsub("%b()","") - lt = lt:gsub("%b{}","") - lt = lt:gsub("%b[]",".0") - -- remove everything that can't be auto-completed - lt = lt:match("[%w_"..q(editor.spec.sep).."]*$") - - -- know now which string is to be completed - local userList = CreateAutoCompList(editor, lt, pos) - - -- don't show if what's typed so far matches one of the options - local right = linetx:sub(localpos+1,#linetx):match("^([%a_]+[%w_]*)") - local left = lt:match("[%w_]*$") -- extract one word on the left (without separators) - if userList and #userList > 0 and not userList:find("%f[%w_]"..left..(right or "").."%f[^%w_]") then - editor:UserListShow(1, userList) - elseif editor:AutoCompActive() then - editor:AutoCompCancel() - end -end - -local ident = "([a-zA-Z_][a-zA-Z_0-9%.%:]*)" -local function getValAtPosition(editor, pos) - local line = editor:LineFromPosition(pos) - local linetx = editor:GetLineDyn(line) - local linestart = editor:PositionFromLine(line) - local localpos = pos-linestart - - local selected = editor:GetSelectionStart() ~= editor:GetSelectionEnd() - and pos >= editor:GetSelectionStart() and pos <= editor:GetSelectionEnd() - - -- check if we have a selected text or an identifier. - -- for an identifier, check fragments on the left and on the right. - -- this is to match 'io' in 'i^o.print' and 'io.print' in 'io.pr^int'. - -- remove square brackets to make tbl[index].x show proper values. - local start = linetx:sub(1,localpos) - :gsub("%b[]", function(s) return ("."):rep(#s) end) - :find(ident.."$") - - local right, funccall = linetx:sub(localpos+1,#linetx):match("^([a-zA-Z_0-9]*)%s*(['\"{%(]?)") - local var = selected - -- GetSelectedText() returns concatenated text when multiple instances - -- are selected, so get the selected text based on start/end - and editor:GetTextRangeDyn(editor:GetSelectionStart(), editor:GetSelectionEnd()) - or (start and linetx:sub(start,localpos):gsub(":",".")..right or nil) - - -- since this function can be called in different contexts, we need - -- to detect function call of different types: - -- 1. foo.b^ar(... -- the cursor (pos) is on the function name - -- 2. foo.bar(..^. -- the cursor (pos) is on the parameter list - -- "var" has value for #1 and the following fragment checks for #2 - - -- check if the style is the right one; this is to ignore - -- comments, strings, numbers (to avoid '1 = 1'), keywords, and such - local goodpos = true - if start and not selected then - local style = bit.band(editor:GetStyleAt(linestart+start),31) - if editor.spec.iscomment[style] - or (MarkupIsAny and MarkupIsAny(style)) -- markup in comments - or editor.spec.isstring[style] - or style == wxstc.wxSTC_LUA_NUMBER - or style == wxstc.wxSTC_LUA_WORD then - goodpos = false - end - end - - local linetxtopos = linetx:sub(1,localpos) - funccall = (#funccall > 0) and goodpos and var - or (linetxtopos..")"):match(ident .. "%s*%b()$") - or (linetxtopos.."}"):match(ident .. "%s*%b{}$") - or (linetxtopos.."'"):match(ident .. "%s*'[^']*'$") - or (linetxtopos..'"'):match(ident .. '%s*"[^"]*"$') - or nil - - -- don't do anything for strings or comments or numbers - if not goodpos then return nil, funccall end - - return var, funccall -end - -local function formatUpToX(s) - local x = math.max(20, ide.config.acandtip.width) - local splitstr = "([ \t]*)(%S*)([ \t]*)(\n?)" - local t = {""} - for prefix, word, suffix, newline in s:gmatch(splitstr) do - if #(t[#t]) + #prefix + #word > x and #t > 0 then - table.insert(t, word..suffix) - else - t[#t] = t[#t]..prefix..word..suffix - end - if #newline > 0 then table.insert(t, "") end - end - return table.concat(t, "\n") -end - -local function callTipFitAndShow(editor, pos, tip) - local point = editor:PointFromPosition(pos) - local height = editor:TextHeight(pos) - local maxlines = math.max(1, math.floor( - math.max(editor:GetSize():GetHeight()-point:GetY()-height, point:GetY())/height-1 - )) - -- cut the tip to not exceed the number of maxlines. - -- move the position to the left if needed to fit. - -- find the longest line in terms of width in pixels. - local maxwidth = 0 - local lines = {} - for line in formatUpToX(tip):gmatch("[^\n]*\n?") do - local width = editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, line) - if width > maxwidth then maxwidth = width end - table.insert(lines, line) - if #lines >= maxlines then - lines[#lines] = lines[#lines]:gsub("%s*\n$","")..'...' - break - end - end - tip = table.concat(lines, '') - - local startpos = editor:PositionFromLine(editor:LineFromPosition(pos)) - local afterwidth = editor:GetSize():GetWidth()-point:GetX() - if maxwidth > afterwidth then - local charwidth = editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, 'A') - pos = math.max(startpos, pos - math.floor((maxwidth - afterwidth) / charwidth)) - end - - editor:CallTipShow(pos, tip) -end - -function EditorCallTip(editor, pos, x, y) - -- don't show anything if the calltip/auto-complete is active; - -- this may happen after typing function name, while the mouse is over - -- a different function or when auto-complete is on for a parameter. - if editor:CallTipActive() or editor:AutoCompActive() then return end - - -- don't activate if the window itself is not active (in the background) - if not ide.frame:IsActive() then return end - - local var, funccall = editor:ValueFromPosition(pos) - -- if this is a value type rather than a function/method call, then use - -- full match to avoid calltip about coroutine.status for "status" vars - local tip = GetTipInfo(editor, funccall or var, false, not funccall) - local limit = ide.config.acandtip.maxlength - if ide.debugger and ide.debugger.server then - if var then - ide.debugger.quickeval(var, function(val) - if #val > limit then val = val:sub(1, limit-3).."..." end - -- check if the mouse position is specified and the mouse has moved, - -- then don't show the tooltip as it's already too late for it. - if x and y then - local mpos = wx.wxGetMousePosition() - if mpos.x ~= x or mpos.y ~= y then return end - end - if PackageEventHandle("onEditorCallTip", editor, val, funccall or var, true) ~= false then - callTipFitAndShow(editor, pos, val) - end - end) - end - elseif tip then - local oncalltip = PackageEventHandle("onEditorCallTip", editor, tip, funccall or var, false) - -- only shorten if shown on mouse-over. Use shortcut to get full info. - local showtooltip = ide.frame.menuBar:FindItem(ID_SHOWTOOLTIP) - local suffix = "...\n" - ..TR("Use '%s' to see full description."):format(showtooltip:GetLabel()) - if x and y and #tip > limit then - tip = tip:sub(1, limit-#suffix):gsub("%W*%w*$","")..suffix - end - if oncalltip ~= false then callTipFitAndShow(editor, pos, tip) end - end -end - --- Indicator handling for functions and local/global variables -local indicator = { - FNCALL = ide:GetIndicator("core.fncall"), - LOCAL = ide:GetIndicator("core.varlocal"), - GLOBAL = ide:GetIndicator("core.varglobal"), - MASKING = ide:GetIndicator("core.varmasking"), - MASKED = ide:GetIndicator("core.varmasked"), -} - -function IndicateFunctionsOnly(editor, lines, linee) - local sindic = styles.indicator - if not (edcfg.showfncall and editor.spec and editor.spec.isfncall) - or not (sindic and sindic.fncall and sindic.fncall.st ~= wxstc.wxSTC_INDIC_HIDDEN) then return end - - local lines = lines or 0 - local linee = linee or editor:GetLineCount()-1 - - if (lines < 0) then return end - - local isfncall = editor.spec.isfncall - local isinvalid = {} - for i,v in pairs(editor.spec.iscomment) do isinvalid[i] = v end - for i,v in pairs(editor.spec.iskeyword0) do isinvalid[i] = v end - for i,v in pairs(editor.spec.isstring) do isinvalid[i] = v end - - editor:SetIndicatorCurrent(indicator.FNCALL) - for line=lines,linee do - local tx = editor:GetLineDyn(line) - local ls = editor:PositionFromLine(line) - editor:IndicatorClearRange(ls, #tx) - - local from = 1 - local off = -1 - while from do - tx = from==1 and tx or string.sub(tx,from) - - local f,t,w = isfncall(tx) - - if (f) then - local p = ls+f+off - local s = bit.band(editor:GetStyleAt(p),31) - if not isinvalid[s] then editor:IndicatorFillRange(p, #w) end - off = off + t - end - from = t and (t+1) - end - end -end - -local delayed = {} - -function IndicateIfNeeded() - local editor = GetEditor() - -- do the current one first - if delayed[editor] then return IndicateAll(editor) end - for ed in pairs(delayed) do return IndicateAll(ed) end -end - --- find all instances of a symbol at pos --- return table with [0] as the definition position (if local) -local function indicateFindInstances(editor, name, pos) - local tokens = editor:GetTokenList() - local instances = {{[-1] = 1}} - local this - for _, token in ipairs(tokens) do - local op = token[1] - - if op == 'EndScope' then -- EndScope has "new" level, so need +1 - if this and token.fpos > pos and this == token.at+1 then break end - - if #instances > 1 and instances[#instances][-1] == token.at+1 then - table.remove(instances) - end - elseif token.name == name then - if op == 'Id' then - table.insert(instances[#instances], token.fpos) - elseif op:find("^Var") then - if this and this == token.at then break end - - -- if new Var is defined at the same level, replace the current frame; - -- if not, add a new one; skip implicit definition of "self" variable. - instances[#instances + (token.at > instances[#instances][-1] and 1 or 0)] - = {[0] = (not token.self and token.fpos or nil), [-1] = token.at} - end - if token.fpos <= pos and pos <= token.fpos+#name then this = instances[#instances][-1] end - end - end - instances[#instances][-1] = nil -- remove the current level - -- only return the list if "this" instance has been found; - -- this is to avoid reporting (improper) instances when checking for - -- comments, strings, table fields, etc. - return this and instances[#instances] or {} -end - -function IndicateAll(editor, lines) - if not ide.config.autoanalyzer then return end - - local d = delayed[editor] - delayed[editor] = nil -- assume this can be finished for now - - -- this function can be called for an editor tab that is already closed - -- when there are still some pending events for it, so handle it. - if not ide:IsValidCtrl(editor) then return end - - -- if markvars is not set in the spec, nothing else to do - if not (editor.spec and editor.spec.marksymbols) then return end - - local indic = styles.indicator or {} - - local pos, vars = d and d[1] or 1, d and d[2] or nil - local start = lines and editor:PositionFromLine(lines)+1 or nil - if d and start and pos >= start then - -- ignore delayed processing as the change is earlier in the text - pos, vars = 1, nil - end - - local tokens = editor:GetTokenList() - - if start then -- if the range is specified - local curindic = editor:GetIndicatorCurrent() - editor:SetIndicatorCurrent(indicator.MASKED) - for n = #tokens, 1, -1 do - local token = tokens[n] - -- find the last token before the range - if not token.nobreak and token.name and token.fpos+#token.name < start then - pos, vars = token.fpos+#token.name, token.context - break - end - -- unmask all variables from the rest of the list - if token[1] == 'Masked' then - editor:IndicatorClearRange(token.fpos-1, #token.name) - end - -- trim the list as it will be re-generated - table.remove(tokens, n) - end - - -- Clear masked indicators from the current position to the end as these - -- will be re-calculated and re-applied based on masking variables. - -- This step is needed as some positions could have shifted after updates. - editor:IndicatorClearRange(pos-1, editor:GetLength()-pos+1) - - editor:SetIndicatorCurrent(curindic) - - -- need to cleanup vars as they may include variables from later - -- fragments (because the cut-point was arbitrary). Also need - -- to clean variables in other scopes, hence getmetatable use. - local vars = vars - while vars do - for name, var in pairs(vars) do - -- remove all variables that are created later than the current pos - -- skip all non-variable elements from the vars table - if type(name) == 'string' then - while type(var) == 'table' and var.fpos and (var.fpos > pos) do - var = var.masked -- restored a masked var - vars[name] = var - end - end - end - vars = getmetatable(vars) and getmetatable(vars).__index - end - else - if pos == 1 then -- if not continuing, then trim the list - tokens = editor:ResetTokenList() - end - end - - local cleared = {} - for _, indic in ipairs {indicator.FNCALL, indicator.LOCAL, indicator.GLOBAL, indicator.MASKING} do - cleared[indic] = pos - end - - local function IndicateOne(indic, pos, length) - editor:SetIndicatorCurrent(indic) - editor:IndicatorClearRange(cleared[indic]-1, pos-cleared[indic]) - editor:IndicatorFillRange(pos-1, length) - cleared[indic] = pos+length - end - - local s = TimeGet() - local canwork = start and 0.010 or 0.100 -- use shorter interval when typing - local f = editor.spec.marksymbols(editor:GetTextDyn(), pos, vars) - while true do - local op, name, lineinfo, vars, at, nobreak = f() - if not op then break end - local var = vars and vars[name] - local token = {op, name=name, fpos=lineinfo, at=at, context=vars, - self = (op == 'VarSelf') or nil, nobreak=nobreak} - if op == 'Function' then - vars['function'] = (vars['function'] or 0) + 1 - end - if op == 'FunctionCall' then - if indic.fncall and edcfg.showfncall then - IndicateOne(indicator.FNCALL, lineinfo, #name) - end - elseif op ~= 'VarNext' and op ~= 'VarInside' and op ~= 'Statement' and op ~= 'String' then - table.insert(tokens, token) - end - - -- indicate local/global variables - if op == 'Id' - and (var and indic.varlocal or not var and indic.varglobal) then - IndicateOne(var and indicator.LOCAL or indicator.GLOBAL, lineinfo, #name) - end - - -- indicate masked values at the same level - if op == 'Var' and var and (var.masked and at == var.masked.at) then - local fpos = var.masked.fpos - -- indicate masked if it's not implicit self - if indic.varmasked and not var.masked.self then - editor:SetIndicatorCurrent(indicator.MASKED) - editor:IndicatorFillRange(fpos-1, #name) - table.insert(tokens, {"Masked", name=name, fpos=fpos, nobreak=nobreak}) - end - - if indic.varmasking then IndicateOne(indicator.MASKING, lineinfo, #name) end - end - -- in some rare cases `nobreak` may be a number indicating a desired - -- position from which to start in case of a break - if lineinfo and nobreak ~= true and (op == 'Statement' or op == 'String') and TimeGet()-s > canwork then - delayed[editor] = {tonumber(nobreak) or lineinfo, vars} - break - end - end - - -- clear indicators till the end of processed fragment - pos = delayed[editor] and delayed[editor][1] or editor:GetLength()+1 - - -- don't clear "masked" indicators as those can be set out of order (so - -- last updated fragment is not always the last in terms of its position); - -- these indicators should be up-to-date to the end of the code fragment. - local funconly = ide.config.editor.showfncall and editor.spec.isfncall - for _, indic in ipairs {indicator.FNCALL, indicator.LOCAL, indicator.GLOBAL, indicator.MASKING} do - -- don't clear "funccall" indicators as those can be set based on - -- IndicateFunctionsOnly processing, which is dealt with separately - if indic ~= indicator.FNCALL or not funconly then IndicateOne(indic, pos, 0) end - end - - local needmore = delayed[editor] ~= nil - if ide.config.outlineinactivity then - if needmore then ide.timers.outline:Stop() - else ide.timers.outline:Start(ide.config.outlineinactivity*1000, wx.wxTIMER_ONE_SHOT) - end - end - return needmore -- request more events if still need to work -end - --- ---------------------------------------------------------------------------- --- Create an editor -function CreateEditor(bare) - local editor = ide:CreateStyledTextCtrl(notebook, editorID, - wx.wxDefaultPosition, wx.wxSize(0, 0), wx.wxBORDER_NONE) - - editorID = editorID + 1 -- increment so they're always unique - - editor.matchon = false - editor.assignscache = false - editor.bom = false - editor.updated = 0 - editor.jumpstack = {} - editor.ctrlcache = {} - editor.tokenlist = {} - editor.onidle = {} - -- populate cache with Ctrl- combinations for workaround on Linux - -- http://wxwidgets.10942.n7.nabble.com/Menu-shortcuts-inconsistentcy-issue-td85065.html - for id, shortcut in pairs(ide.config.keymap) do - local key = shortcut:match('^Ctrl[-+](.)$') - if key then editor.ctrlcache[key:byte()] = id end - end - - -- populate editor keymap with configured combinations - for _, map in ipairs(edcfg.keymap or {}) do - local key, mod, cmd, os = unpack(map) - if not os or os == ide.osname then - if cmd then - editor:CmdKeyAssign(key, mod, cmd) - else - editor:CmdKeyClear(key, mod) - end - end - end - - editor:SetBufferedDraw(not ide.config.hidpi and true or false) - editor:StyleClearAll() - - editor:SetFont(ide.font.eNormal) - editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.eNormal) - - editor:SetTabWidth(tonumber(edcfg.tabwidth) or 2) - editor:SetIndent(tonumber(edcfg.tabwidth) or 2) - editor:SetUseTabs(edcfg.usetabs and true or false) - editor:SetIndentationGuides(tonumber(edcfg.indentguide) or (edcfg.indentguide and true or false)) - editor:SetViewWhiteSpace(edcfg.whitespace and true or false) - - if (edcfg.usewrap) then - editor:SetWrapMode(edcfg.wrapmode) - editor:SetWrapStartIndent(0) - if ide.wxver >= "2.9.5" then - if edcfg.wrapflags then - editor:SetWrapVisualFlags(tonumber(edcfg.wrapflags) or wxstc.wxSTC_WRAPVISUALFLAG_NONE) - end - if edcfg.wrapstartindent then - editor:SetWrapStartIndent(tonumber(edcfg.wrapstartindent) or 0) - end - if edcfg.wrapindentmode then - editor:SetWrapIndentMode(edcfg.wrapindentmode) - end - end - else - editor:SetScrollWidth(100) -- set default width - editor:SetScrollWidthTracking(1) -- enable width auto-adjustment - end - - if edcfg.defaulteol == wxstc.wxSTC_EOL_CRLF - or edcfg.defaulteol == wxstc.wxSTC_EOL_LF then - editor:SetEOLMode(edcfg.defaulteol) - -- else: keep wxStyledTextCtrl default behavior (CRLF on Windows, LF on Unix) - end - - editor:SetCaretLineVisible(edcfg.caretline and true or false) - - editor:SetVisiblePolicy(wxstc.wxSTC_VISIBLE_STRICT, 3) - - editor:SetMarginType(margin.LINENUMBER, wxstc.wxSTC_MARGIN_NUMBER) - editor:SetMarginMask(margin.LINENUMBER, 0) - editor:SetMarginWidth(margin.LINENUMBER, - math.floor(linenumlen * editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, "8"))) - - editor:SetMarginWidth(margin.MARKER, 18) - editor:SetMarginType(margin.MARKER, wxstc.wxSTC_MARGIN_SYMBOL) - editor:SetMarginMask(margin.MARKER, 0xffffffff - wxstc.wxSTC_MASK_FOLDERS) - editor:SetMarginSensitive(margin.MARKER, true) - - editor:MarkerDefine(StylesGetMarker("currentline")) - editor:MarkerDefine(StylesGetMarker("breakpoint")) - editor:MarkerDefine(StylesGetMarker("bookmark")) - - if edcfg.fold then - editor:SetMarginWidth(margin.FOLD, 18) - editor:SetMarginType(margin.FOLD, wxstc.wxSTC_MARGIN_SYMBOL) - editor:SetMarginMask(margin.FOLD, wxstc.wxSTC_MASK_FOLDERS) - editor:SetMarginSensitive(margin.FOLD, true) - end - - editor:SetFoldFlags(tonumber(edcfg.foldflags) or wxstc.wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED) - - if ide.wxver >= "2.9.5" then - -- allow multiple selection and multi-cursor editing if supported - editor:SetMultipleSelection(1) - editor:SetAdditionalCaretsBlink(1) - editor:SetAdditionalSelectionTyping(1) - -- allow extra ascent/descent - editor:SetExtraAscent(tonumber(edcfg.extraascent) or 0) - editor:SetExtraDescent(tonumber(edcfg.extradescent) or 0) - end - - do - local fg, bg = wx.wxWHITE, wx.wxColour(128, 128, 128) - local foldtype = foldtypes[edcfg.foldtype] or foldtypes.box - local foldmarkers = foldtypes[0] - for m = 1, #foldmarkers do - editor:MarkerDefine(foldmarkers[m], foldtype[m] or wxstc.wxSTC_MARK_EMPTY, fg, bg) - end - bg:delete() - end - - if edcfg.calltipdelay and edcfg.calltipdelay > 0 then - editor:SetMouseDwellTime(edcfg.calltipdelay) - end - - editor:AutoCompSetIgnoreCase(ide.config.acandtip.ignorecase) - if (ide.config.acandtip.strategy > 0) then - editor:AutoCompSetAutoHide(0) - editor:AutoCompStops([[ \n\t=-+():.,;*/!"'$%&~'#°^@?´`<>][|}{]]) - end - - function editor:GetTokenList() return self.tokenlist end - function editor:ResetTokenList() self.tokenlist = {}; return self.tokenlist end - - function editor:SetupKeywords(...) return SetupKeywords(self, ...) end - function editor:ValueFromPosition(pos) return getValAtPosition(self, pos) end - - function editor:MarkerGotoNext(marker) - local value = 2^marker - local line = editor:MarkerNext(editor:GetCurrentLine()+1, value) - if line == -1 then line = editor:MarkerNext(0, value) end - if line == -1 then return end - editor:GotoLine(line) - editor:EnsureVisibleEnforcePolicy(line) - return line - end - function editor:MarkerGotoPrev(marker) - local value = 2^marker - local line = editor:MarkerPrevious(editor:GetCurrentLine()-1, value) - if line == -1 then line = editor:MarkerPrevious(editor:GetLineCount(), value) end - if line == -1 then return end - editor:GotoLine(line) - editor:EnsureVisibleEnforcePolicy(line) - return line - end - function editor:MarkerToggle(marker, line, value) - line = line or editor:GetCurrentLine() - local isset = bit.band(editor:MarkerGet(line), 2^marker) > 0 - if value ~= nil and isset == value then return end - if isset then - editor:MarkerDelete(line, marker) - else - editor:MarkerAdd(line, marker) - end - PackageEventHandle("onEditorMarkerUpdate", editor, marker, line, not isset) - end - - function editor:BookmarkToggle(...) return self:MarkerToggle((StylesGetMarker("bookmark")), ...) end - function editor:BreakpointToggle(line, ...) - line = line or self:GetCurrentLine() - return DebuggerToggleBreakpoint(self, line, ...) - end - - function editor:DoWhenIdle(func) table.insert(self.onidle, func) end - - -- GotoPos should work by itself, but it doesn't (wx 2.9.5). - -- This is likely because the editor window hasn't been refreshed yet, - -- so its LinesOnScreen method returns 0/-1, which skews the calculations. - -- To avoid this, the caret line is made visible at the first opportunity. - do - local redolater - function editor:GotoPosDelayed(pos) - local badtime = self:LinesOnScreen() <= 0 -- -1 on OSX, 0 on Windows - if pos then - if badtime then - redolater = pos - -- without this GotoPos the content is not scrolled correctly on - -- Windows, but with this it's not scrolled correctly on OSX. - if ide.osname ~= 'Macintosh' then self:GotoPos(pos) end - else - redolater = nil - self:GotoPosEnforcePolicy(pos) - end - elseif not badtime and redolater then - -- reset the left margin first to make sure that the position - -- is set "from the left" to get the best content displayed. - self:SetXOffset(0) - self:GotoPosEnforcePolicy(redolater) - redolater = nil - end - end - end - - if bare then return editor end -- bare editor doesn't have any event handlers - - editor.ev = {} - editor:Connect(wxstc.wxEVT_STC_MARGINCLICK, - function (event) - local line = editor:LineFromPosition(event:GetPosition()) - local marginno = event:GetMargin() - if marginno == margin.MARKER then - DebuggerToggleBreakpoint(editor, line) - elseif marginno == margin.FOLD then - local header = bit.band(editor:GetFoldLevel(line), - wxstc.wxSTC_FOLDLEVELHEADERFLAG) == wxstc.wxSTC_FOLDLEVELHEADERFLAG - if wx.wxGetKeyState(wx.WXK_SHIFT) and wx.wxGetKeyState(wx.WXK_CONTROL) then - editor:FoldSome() - elseif header then - editor:ToggleFold(line) - end - end - end) - - editor:Connect(wxstc.wxEVT_STC_MODIFIED, - function (event) - if (editor.assignscache and editor:GetCurrentLine() ~= editor.assignscache.line) then - editor.assignscache = false - end - local evtype = event:GetModificationType() - if bit.band(evtype, wxstc.wxSTC_MOD_CHANGEMARKER) == 0 then - -- this event is being called on OSX too frequently, so skip these notifications - editor.updated = TimeGet() - end - local pos = event:GetPosition() - local firstLine = editor:LineFromPosition(pos) - local inserted = bit.band(evtype, wxstc.wxSTC_MOD_INSERTTEXT) ~= 0 - local deleted = bit.band(evtype, wxstc.wxSTC_MOD_DELETETEXT) ~= 0 - if (inserted or deleted) then - SetAutoRecoveryMark() - - local linesChanged = inserted and event:GetLinesAdded() or 0 - -- collate events if they are for the same line - local events = #editor.ev - if events == 0 or editor.ev[events][1] ~= firstLine then - editor.ev[events+1] = {firstLine, linesChanged} - elseif events > 0 and editor.ev[events][1] == firstLine then - editor.ev[events][2] = math.max(editor.ev[events][2], linesChanged) - end - DynamicWordsAdd(editor, nil, firstLine, linesChanged) - end - - local beforeInserted = bit.band(evtype,wxstc.wxSTC_MOD_BEFOREINSERT) ~= 0 - local beforeDeleted = bit.band(evtype,wxstc.wxSTC_MOD_BEFOREDELETE) ~= 0 - - if (beforeInserted or beforeDeleted) then - -- unfold the current line being changed if folded, but only if one selection - local lastLine = editor:LineFromPosition(pos+event:GetLength()) - local selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1 - if (not editor:GetFoldExpanded(firstLine) - or not editor:GetLineVisible(firstLine) - or not editor:GetLineVisible(lastLine)) - and selections == 1 then - for line = firstLine, lastLine do - if not editor:GetLineVisible(line) then editor:ToggleFold(editor:GetFoldParent(line)) end - end - end - end - - -- hide calltip/auto-complete after undo/redo/delete - local undodelete = (wxstc.wxSTC_MOD_DELETETEXT - + wxstc.wxSTC_PERFORMED_UNDO + wxstc.wxSTC_PERFORMED_REDO) - if bit.band(evtype, undodelete) ~= 0 then - editor:DoWhenIdle(function(editor) - if editor:CallTipActive() then editor:CallTipCancel() end - if editor:AutoCompActive() then editor:AutoCompCancel() end - end) - end - - if ide.config.acandtip.nodynwords then return end - -- only required to track changes - - if beforeDeleted then - local text = editor:GetTextRangeDyn(pos, pos+event:GetLength()) - local _, numlines = text:gsub("\r?\n","%1") - DynamicWordsRem(editor,nil,firstLine, numlines) - end - if beforeInserted then - DynamicWordsRem(editor,nil,firstLine, 0) - end - end) - - editor:Connect(wxstc.wxEVT_STC_CHARADDED, - function (event) - local LF = string.byte("\n") - local ch = event:GetKey() - local pos = editor:GetCurrentPos() - local line = editor:GetCurrentLine() - local linetx = editor:GetLineDyn(line) - local linestart = editor:PositionFromLine(line) - local localpos = pos-linestart - local linetxtopos = linetx:sub(1,localpos) - - if PackageEventHandle("onEditorCharAdded", editor, event) == false then - -- this event has already been handled - elseif (ch == LF) then - -- auto-indent - if (line > 0) then - local indent = editor:GetLineIndentation(line - 1) - local linedone = editor:GetLineDyn(line - 1) - - -- if the indentation is 0 and the current line is not empty, - -- but the previous line is empty, then take indentation from the - -- current line (instead of the previous one). This may happen when - -- CR is hit at the beginning of a line (rather than at the end). - if indent == 0 and not linetx:match("^[\010\013]*$") - and linedone:match("^[\010\013]*$") then - indent = editor:GetLineIndentation(line) - end - - local ut = editor:GetUseTabs() - local tw = ut and editor:GetTabWidth() or editor:GetIndent() - local style = bit.band(editor:GetStyleAt(editor:PositionFromLine(line-1)), 31) - - if edcfg.smartindent - -- don't apply smartindent to multi-line comments or strings - and not (editor.spec.iscomment[style] - or editor.spec.isstring[style] - or (MarkupIsAny and MarkupIsAny(style))) - and editor.spec.isdecindent and editor.spec.isincindent then - local closed, blockend = editor.spec.isdecindent(linedone) - local opened = editor.spec.isincindent(linedone) - - -- if the current block is already indented, skip reverse indenting - if (line > 1) and (closed > 0 or blockend > 0) - and editor:GetLineIndentation(line-2) > indent then - -- adjust opened first; this is needed when use ENTER after }) - if blockend == 0 then opened = opened + closed end - closed, blockend = 0, 0 - end - editor:SetLineIndentation(line-1, indent - tw * closed) - indent = indent + tw * (opened - blockend) - if indent < 0 then indent = 0 end - end - editor:SetLineIndentation(line, indent) - - indent = ut and (indent / tw) or indent - editor:GotoPos(editor:GetCurrentPos()+indent) - end - - elseif ch == ("("):byte() then - local tip = GetTipInfo(editor,linetxtopos,ide.config.acandtip.shorttip) - if tip then - if editor:CallTipActive() then editor:CallTipCancel() end - if PackageEventHandle("onEditorCallTip", editor, tip) ~= false then - callTipFitAndShow(editor, pos, tip) - end - end - - elseif ide.config.autocomplete then -- code completion prompt - local trigger = linetxtopos:match("["..editor.spec.sep.."%w_]+$") - if trigger and (#trigger > 1 or trigger:match("["..editor.spec.sep.."]")) then - editor:DoWhenIdle(function(editor) EditorAutoComplete(editor) end) - end - end - end) - - editor:Connect(wxstc.wxEVT_STC_DWELLSTART, - function (event) - -- on Linux DWELLSTART event seems to be generated even for those - -- editor windows that are not active. What's worse, when generated - -- the event seems to report "old" position when retrieved using - -- event:GetX and event:GetY, so instead we use wxGetMousePosition. - local linux = ide.osname == 'Unix' - if linux and editor ~= GetEditor() then return end - - -- check if this editor has focus; it may not when Stack/Watch window - -- is on top, but DWELL events are still triggered in this case. - -- Don't want to show calltip as it is still shown when the focus - -- is switched to a different application. - local focus = editor:FindFocus() - if focus and focus:GetId() ~= editor:GetId() then return end - - -- event:GetX() and event:GetY() positions don't correspond to - -- the correct positions calculated using ScreenToClient (at least - -- on Windows and Linux), so use what's calculated. - local mpos = wx.wxGetMousePosition() - local cpos = editor:ScreenToClient(mpos) - local position = editor:PositionFromPointClose(cpos.x, cpos.y) - if position ~= wxstc.wxSTC_INVALID_POSITION then - EditorCallTip(editor, position, mpos.x, mpos.y) - end - event:Skip() - end) - - editor:Connect(wxstc.wxEVT_STC_DWELLEND, - function (event) - if editor:CallTipActive() then editor:CallTipCancel() end - event:Skip() - end) - - editor:Connect(wx.wxEVT_KILL_FOCUS, - function (event) - -- on OSX clicking on scrollbar in the popup is causing the editor to lose focus, - -- which causes canceling of auto-complete, which later cause crash because - -- the window is destroyed in wxwidgets after already being closed. Skip on OSX. - if ide.osname ~= 'Macintosh' and editor:AutoCompActive() then editor:AutoCompCancel() end - PackageEventHandle("onEditorFocusLost", editor) - event:Skip() - end) - - local eol = { - [wxstc.wxSTC_EOL_CRLF] = "\r\n", - [wxstc.wxSTC_EOL_LF] = "\n", - [wxstc.wxSTC_EOL_CR] = "\r", - } - local function addOneLine(editor, adj) - local pos = editor:GetLineEndPosition(editor:LineFromPosition(editor:GetCurrentPos())+(adj or 0)) - local added = eol[editor:GetEOLMode()] or "\n" - editor:InsertTextDyn(pos, added) - editor:SetCurrentPos(pos+#added) - - local ev = wxstc.wxStyledTextEvent(wxstc.wxEVT_STC_CHARADDED) - ev:SetKey(string.byte("\n")) - editor:AddPendingEvent(ev) - end - - editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION, - function (event) - if PackageEventHandle("onEditorUserlistSelection", editor, event) == false then - return - end - - -- if used Shift-Enter, then skip auto complete and just do Enter - if wx.wxGetKeyState(wx.WXK_SHIFT) then return addOneLine(editor) end - - if ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then - local text = event:GetText() - -- capture all positions as the selection may change - local positions = {} - for s = 0, editor:GetSelections()-1 do - table.insert(positions, editor:GetSelectionNCaret(s)) - end - -- process all selections from last to first - table.sort(positions) - local mainpos = editor:GetSelectionNCaret(editor:GetMainSelection()) - - editor:BeginUndoAction() - for s = #positions, 1, -1 do - local pos = positions[s] - local startpos = editor:WordStartPosition(pos, true) - editor:SetSelection(startpos, pos) - editor:ReplaceSelection(text) - -- if this is the main position, save new cursor position to restore - if pos == mainpos then mainpos = editor:GetCurrentPos() - elseif pos < mainpos then - -- adjust main position as earlier changes may affect it - mainpos = mainpos + #text - (pos - startpos) - end - end - editor:EndUndoAction() - - editor:GotoPos(mainpos) - else - local pos = editor:GetCurrentPos() - local startpos = editor:WordStartPosition(pos, true) - local endpos = editor:WordEndPosition(pos, true) - editor:SetSelection(startpos, ide.config.acandtip.droprest and endpos or pos) - editor:ReplaceSelection(event:GetText()) - end - end) - - editor:Connect(wxstc.wxEVT_STC_SAVEPOINTREACHED, - function () - local doc = ide:GetDocument(editor) - if doc then doc:SetModified(false) end - end) - - editor:Connect(wxstc.wxEVT_STC_SAVEPOINTLEFT, - function () - local doc = ide:GetDocument(editor) - if doc then doc:SetModified(true) end - end) - - -- "updateStatusText" should be called in UPDATEUI event, but it creates - -- several performance problems on Windows (using wx2.9.5+) when - -- brackets or backspace is used (very slow screen repaint with 0.5s delay). - -- Moving it to PAINTED event creates problems on OSX (using wx2.9.5+), - -- where refresh of R/W and R/O status in the status bar is delayed. - - editor:Connect(wxstc.wxEVT_STC_PAINTED, - function (event) - PackageEventHandle("onEditorPainted", editor, event) - - if ide.osname == 'Windows' then - -- STC_PAINTED is called on multiple editors when they point to - -- the same document; only update status for the active one - if notebook:GetSelection() == notebook:GetPageIndex(editor) then - updateStatusText(editor) - end - - if edcfg.usewrap ~= true and editor:AutoCompActive() then - -- showing auto-complete list leaves artifacts on the screen, - -- which can only be fixed by a forced refresh. - -- shows with wxSTC 3.21 and both wxwidgets 2.9.5 and 3.1 - editor:Update() - editor:Refresh() - end - end - - -- adjust line number margin, but only if it's already shown - local linecount = #tostring(editor:GetLineCount()) + 0.5 - local mwidth = editor:GetMarginWidth(margin.LINENUMBER) - if mwidth > 0 then - local width = math.max(linecount, linenumlen) * editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, "8") - if mwidth ~= width then editor:SetMarginWidth(margin.LINENUMBER, math.floor(width)) end - end - end) - - editor.processedUpdateContent = 0 - editor:Connect(wxstc.wxEVT_STC_UPDATEUI, - function (event) - -- some of UPDATEUI events may be triggered as the result of editor updates - -- from subsequent events (like PAINTED, which happens in documentmap plugin). - -- the reason for the `processed` check is that it is not possible - -- to completely skip all of these updates as this causes the issue - -- of markup styling becoming visible after text deletion by Backspace. - -- to avoid this, we allow the first update after any updates caused - -- by real changes; the rest of UPDATEUI events are skipped. - -- (use direct comparison, as need to skip events that just update content) - if event:GetUpdated() == wxstc.wxSTC_UPDATE_CONTENT - and not next(editor.ev) then - if editor.processedUpdateContent > 1 then return end - else - editor.processedUpdateContent = 0 - end - editor.processedUpdateContent = editor.processedUpdateContent + 1 - - PackageEventHandle("onEditorUpdateUI", editor, event) - - if ide.osname ~= 'Windows' then updateStatusText(editor) end - - editor:GotoPosDelayed() - updateBraceMatch(editor) - local minupdated - for _,iv in ipairs(editor.ev) do - local line = iv[1] - if not minupdated or line < minupdated then minupdated = line end - IndicateFunctionsOnly(editor,line,line+iv[2]) - end - if minupdated then - local ok, res = pcall(IndicateAll, editor, minupdated) - if not ok then DisplayOutputLn("Internal error: ",res,minupdated) end - end - local firstvisible = editor:DocLineFromVisible(editor:GetFirstVisibleLine()) - local lastline = math.min(editor:GetLineCount(), - firstvisible + editor:LinesOnScreen()) - -- lastline - editor:LinesOnScreen() can get negative; fix it - local firstline = math.min(math.max(0, lastline - editor:LinesOnScreen()), - firstvisible) - MarkupStyle(editor,minupdated or firstline,lastline) - editor.ev = {} - end) - - editor:Connect(wx.wxEVT_IDLE, - function (event) - while #editor.onidle > 0 do table.remove(editor.onidle)(editor) end - end) - - editor:Connect(wx.wxEVT_LEFT_DOWN, - function (event) - if MarkupHotspotClick then - local position = editor:PositionFromPointClose(event:GetX(),event:GetY()) - if position ~= wxstc.wxSTC_INVALID_POSITION then - if MarkupHotspotClick(position, editor) then return end - end - end - - if event:ControlDown() and event:AltDown() - -- ide.wxver >= "2.9.5"; fix after GetModifiers is added to wxMouseEvent in wxlua - and not event:ShiftDown() and not event:MetaDown() then - local point = event:GetPosition() - local pos = editor:PositionFromPointClose(point.x, point.y) - local value = pos ~= wxstc.wxSTC_INVALID_POSITION and editor:ValueFromPosition(pos) or nil - local instances = value and indicateFindInstances(editor, value, pos+1) - if instances and instances[0] then - navigateToPosition(editor, pos, instances[0]-1, #value) - return - end - end - event:Skip() - end) - - if edcfg.nomousezoom then - -- disable zoom using mouse wheel as it triggers zooming when scrolling - -- on OSX with kinetic scroll and then pressing CMD. - editor:Connect(wx.wxEVT_MOUSEWHEEL, - function (event) - if wx.wxGetKeyState(wx.WXK_CONTROL) then return end - event:Skip() - end) - end - - local inhandler = false - editor:Connect(wx.wxEVT_SET_FOCUS, - function (event) - event:Skip() - if inhandler or ide.exitingProgram then return end - inhandler = true - PackageEventHandle("onEditorFocusSet", editor) - isFileAlteredOnDisk(editor) - inhandler = false - end) - - editor:Connect(wx.wxEVT_KEY_DOWN, - function (event) - local keycode = event:GetKeyCode() - local mod = event:GetModifiers() - local first, last = 0, notebook:GetPageCount()-1 - if PackageEventHandle("onEditorKeyDown", editor, event) == false then - -- this event has already been handled - elseif keycode == wx.WXK_ESCAPE then - if editor:CallTipActive() or editor:AutoCompActive() then - event:Skip() - elseif ide.findReplace:IsShown() then - ide.findReplace:Hide() - elseif ide:GetMainFrame():IsFullScreen() then - ShowFullScreen(false) - end - -- Ctrl-Home and Ctrl-End don't work on OSX with 2.9.5+; fix it - elseif ide.osname == 'Macintosh' and ide.wxver >= "2.9.5" - and (mod == wx.wxMOD_RAW_CONTROL or mod == (wx.wxMOD_RAW_CONTROL + wx.wxMOD_SHIFT)) - and (keycode == wx.WXK_HOME or keycode == wx.WXK_END) then - local pos = keycode == wx.WXK_HOME and 0 or editor:GetLength() - if event:ShiftDown() -- mark selection and scroll to caret - then editor:SetCurrentPos(pos) editor:EnsureCaretVisible() - else editor:GotoPos(pos) end - elseif mod == wx.wxMOD_RAW_CONTROL and keycode == wx.WXK_PAGEUP - or mod == (wx.wxMOD_RAW_CONTROL + wx.wxMOD_SHIFT) and keycode == wx.WXK_TAB then - if notebook:GetSelection() == first - then notebook:SetSelection(last) - else notebook:AdvanceSelection(false) end - elseif mod == wx.wxMOD_RAW_CONTROL - and (keycode == wx.WXK_PAGEDOWN or keycode == wx.WXK_TAB) then - if notebook:GetSelection() == last - then notebook:SetSelection(first) - else notebook:AdvanceSelection(true) end - elseif (keycode == wx.WXK_DELETE or keycode == wx.WXK_BACK) - and (mod == wx.wxMOD_NONE) then - -- Delete and Backspace behave the same way for selected text - if #(editor:GetSelectedText()) > 0 then - editor:ClearAny() - else - local pos = editor:GetCurrentPos() - if keycode == wx.WXK_BACK then - pos = pos - 1 - if pos < 0 then return end - end - - -- check if the modification is to one of "invisible" characters. - -- if not, proceed with "normal" processing as there are other - -- events that may depend on Backspace, for example, re-calculating - -- auto-complete suggestions. - local style = bit.band(editor:GetStyleAt(pos), 31) - if not MarkupIsSpecial or not MarkupIsSpecial(style) then - -- if BACKSPACE is used at tab stop, with spaces for indentation, - -- and only whilespaces on the left, reduce indent - if edcfg.backspaceunindent and keycode == wx.WXK_BACK and not editor:GetUseTabs() then - -- get the line number from the *current* position of the cursor - local line = editor:LineFromPosition(pos+1) - local text = editor:GetLineDyn(line):sub(1, pos-editor:PositionFromLine(line)+1) - local tw = editor:GetIndent() - -- if on the tab stop position and only white spaces on the left - if text:find('^%s+$') and #text % tw == 0 then - editor:SetLineIndentation(line, editor:GetLineIndentation(line) - tw) - editor:GotoPos(pos+1-tw) - return - end - end - event:Skip() - return - end - - editor:SetTargetStart(pos) - editor:SetTargetEnd(pos+1) - editor:ReplaceTarget("") - end - elseif mod == wx.wxMOD_ALT and keycode == wx.WXK_LEFT then - -- if no "jump back" is needed, then do normal processing as this - -- combination can be mapped to some action - if not navigateBack(editor) then event:Skip() end - elseif (keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER) - and (mod == wx.wxMOD_CONTROL or mod == (wx.wxMOD_CONTROL + wx.wxMOD_SHIFT)) then - addOneLine(editor, mod == (wx.wxMOD_CONTROL + wx.wxMOD_SHIFT) and -1 or 0) - elseif ide.osname == "Unix" and ide.wxver >= "2.9.5" - and mod == wx.wxMOD_CONTROL and editor.ctrlcache[keycode] then - ide.frame:AddPendingEvent(wx.wxCommandEvent( - wx.wxEVT_COMMAND_MENU_SELECTED, editor.ctrlcache[keycode])) - else - if ide.osname == 'Macintosh' and mod == wx.wxMOD_META then - return -- ignore a key press if Command key is also pressed - end - event:Skip() - end - end) - - local function selectAllInstances(instances, name, curpos) - local this - local idx = 0 - for _, pos in pairs(instances) do - pos = pos - 1 -- positions are 0-based in Scintilla - if idx == 0 then - -- clear selections first as there seems to be a bug (Scintilla 3.2.3) - -- that doesn't reset selection after right mouse click. - editor:ClearSelections() - editor:SetSelection(pos, pos+#name) - else - editor:AddSelection(pos+#name, pos) - end - - -- check if this is the current selection - if curpos >= pos and curpos <= pos+#name then this = idx end - idx = idx + 1 - end - if this then editor:SetMainSelection(this) end - -- set the current name as the search value to make subsequence searches look for it - ide.findReplace:SetFind(name) - end - - editor:Connect(wxstc.wxEVT_STC_DOUBLECLICK, - function(event) - -- only activate selection of instances on Ctrl/Cmd-DoubleClick - if event:GetModifiers() == wx.wxMOD_CONTROL then - local pos = event:GetPosition() - local value = pos ~= wxstc.wxSTC_INVALID_POSITION and editor:ValueFromPosition(pos) or nil - local instances = value and indicateFindInstances(editor, value, pos+1) - if instances and (instances[0] or #instances > 0) then - selectAllInstances(instances, value, pos) - return - end - end - - event:Skip() - end) - - editor:Connect(wxstc.wxEVT_STC_ZOOM, - function(event) - -- if Shift+Zoom is used, then zoom all editors, not just the current one - if wx.wxGetKeyState(wx.WXK_SHIFT) then - local zoom = editor:GetZoom() - for _, doc in pairs(openDocuments) do - -- check the editor zoom level to avoid recursion - if doc.editor:GetZoom() ~= zoom then doc.editor:SetZoom(zoom) end - end - end - event:Skip() - end) - - local pos, value, instances - editor:Connect(wx.wxEVT_CONTEXT_MENU, - function (event) - local point = editor:ScreenToClient(event:GetPosition()) - pos = editor:PositionFromPointClose(point.x, point.y) - value = pos ~= wxstc.wxSTC_INVALID_POSITION and editor:ValueFromPosition(pos) or nil - instances = value and indicateFindInstances(editor, value, pos+1) - - local occurrences = (not instances or #instances == 0) and "" - or (" (%d)"):format(#instances+(instances[0] and 1 or 0)) - local line = instances and instances[0] and editor:LineFromPosition(instances[0]-1)+1 - local def = line and " ("..TR("on line %d"):format(line)..")" or "" - local selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1 - - local menu = wx.wxMenu { - { ID_UNDO, TR("&Undo") }, - { ID_REDO, TR("&Redo") }, - { }, - { ID_CUT, TR("Cu&t") }, - { ID_COPY, TR("&Copy") }, - { ID_PASTE, TR("&Paste") }, - { ID_SELECTALL, TR("Select &All") }, - { }, - { ID_GOTODEFINITION, TR("Go To Definition")..def }, - { ID_RENAMEALLINSTANCES, TR("Rename All Instances")..occurrences }, - { ID_REPLACEALLSELECTIONS, TR("Replace All Selections") }, - { }, - { ID_QUICKADDWATCH, TR("Add Watch Expression") }, - { ID_QUICKEVAL, TR("Evaluate In Console") }, - { ID_ADDTOSCRATCHPAD, TR("Add To Scratchpad") }, - { ID_RUNTO, TR("Run To Cursor") }, - } - - menu:Enable(ID_GOTODEFINITION, instances and instances[0]) - menu:Enable(ID_RENAMEALLINSTANCES, instances and (instances[0] or #instances > 0) - or editor:GetSelectionStart() ~= editor:GetSelectionEnd()) - menu:Enable(ID_REPLACEALLSELECTIONS, selections > 1) - menu:Enable(ID_QUICKADDWATCH, value ~= nil) - menu:Enable(ID_QUICKEVAL, value ~= nil) - - local debugger = ide.debugger - menu:Enable(ID_ADDTOSCRATCHPAD, debugger.scratchpad - and debugger.scratchpad.editors and not debugger.scratchpad.editors[editor]) - - -- disable calltips that could open over the menu - local dwelltime = editor:GetMouseDwellTime() - editor:SetMouseDwellTime(0) -- disable dwelling - - -- cancel calltip if it's already shown as it interferes with popup menu - if editor:CallTipActive() then editor:CallTipCancel() end - - PackageEventHandle("onMenuEditor", menu, editor, event) - - editor:PopupMenu(menu) - editor:SetMouseDwellTime(dwelltime) -- restore dwelling - end) - - editor:Connect(ID_RUNTO, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - if pos ~= wxstc.wxSTC_INVALID_POSITION then - ide:GetDebugger().runto(editor, editor:LineFromPosition(pos)) - end - end) - - editor:Connect(ID_GOTODEFINITION, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - if value and instances[0] then - navigateToPosition(editor, editor:GetCurrentPos(), instances[0]-1, #value) - end - end) - - editor:Connect(ID_RENAMEALLINSTANCES, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - if value and pos then - if not (instances and (instances[0] or #instances > 0)) then - -- if multiple instances (of a variable) are not detected, - -- then simply find all instances of (selected) `value` - instances = {} - local length, pos = editor:GetLength(), 0 - while true do - editor:SetTargetStart(pos) - editor:SetTargetEnd(length) - pos = editor:SearchInTarget(value) - if pos == -1 then break end - table.insert(instances, pos+1) - pos = pos + #value - end - end - selectAllInstances(instances, value, pos) - end - end) - - editor:Connect(ID_REPLACEALLSELECTIONS, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - local main = editor:GetMainSelection() - local text = wx.wxGetTextFromUser( - TR("Enter replacement text"), - TR("Replace All Selections"), - editor:GetTextRangeDyn(editor:GetSelectionNStart(main), editor:GetSelectionNEnd(main)) - ) - if not text or text == "" then return end - - editor:BeginUndoAction() - for s = 0, editor:GetSelections()-1 do - local selst, selend = editor:GetSelectionNStart(s), editor:GetSelectionNEnd(s) - editor:SetTargetStart(selst) - editor:SetTargetEnd(selend) - editor:ReplaceTarget(text) - editor:SetSelectionNStart(s, selst) - editor:SetSelectionNEnd(s, selst+#text) - end - editor:EndUndoAction() - editor:SetMainSelection(main) - end) - - editor:Connect(ID_QUICKADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) ide:AddWatch(value) end) - - editor:Connect(ID_QUICKEVAL, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) ShellExecuteCode(value) end) - - editor:Connect(ID_ADDTOSCRATCHPAD, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) DebuggerScratchpadOn(editor) end) - - return editor -end - --- ---------------------------------------------------------------------------- --- Add an editor to the notebook -function AddEditor(editor, name) - assert(notebook:GetPageIndex(editor) == -1, "Editor being added is not in the notebook: failed") - - -- set the document properties - local id = editor:GetId() - local document = setmetatable({}, ide.proto.Document) - document.editor = editor - document.fileName = name - document.filePath = nil - document.modTime = nil - document.isModified = false - openDocuments[id] = document - - -- add page only after document is created as there may be handlers - -- that expect the document (for example, onEditorFocusSet) - if not notebook:AddPage(editor, name, true) then - openDocuments[id] = nil - return - else - document.index = notebook:GetPageIndex(editor) - return document - end -end - -function GetSpec(ext,forcespec) - local spec = forcespec - - -- search proper spec - -- allow forcespec for "override" - if ext and not spec then - for _,curspec in pairs(ide.specs) do - local exts = curspec.exts - if (exts) then - for _,curext in ipairs(exts) do - if (curext == ext) then - spec = curspec - break - end - end - if (spec) then - break - end - end - end - end - return spec -end - -function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic) - local lexerstyleconvert = nil - local spec = forcespec or GetSpec(ext) - -- found a spec setup lexers and keywords - if spec then - editor:SetLexer(spec.lexer or wxstc.wxSTC_LEX_NULL) - lexerstyleconvert = spec.lexerstyleconvert - - if (spec.keywords) then - for i,words in ipairs(spec.keywords) do - editor:SetKeyWords(i-1,words) - end - end - - editor.api = GetApi(spec.apitype or "none") - editor.spec = spec - else - editor:SetLexer(wxstc.wxSTC_LEX_NULL) - editor:SetKeyWords(0, "") - - editor.api = GetApi("none") - editor.spec = ide.specs.none - end - - -- need to set folding property after lexer is set, otherwise - -- the folds are not shown (wxwidgets 2.9.5) - if edcfg.fold then - editor:SetProperty("fold", "1") - editor:SetProperty("fold.html", "1") - editor:SetProperty("fold.compact", edcfg.foldcompact and "1" or "0") - editor:SetProperty("fold.comment", "1") - end - - -- quickfix to prevent weird looks, otherwise need to update styling mechanism for cpp - -- cpp "greyed out" styles are styleid + 64 - editor:SetProperty("lexer.cpp.track.preprocessor", "0") - editor:SetProperty("lexer.cpp.update.preprocessor", "0") - - -- create italic font if only main font is provided - if font and not fontitalic then - fontitalic = wx.wxFont(font) - fontitalic:SetStyle(wx.wxFONTSTYLE_ITALIC) - end - - StylesApplyToEditor(styles or ide.config.styles, editor, - font or ide.font.eNormal,fontitalic or ide.font.eItalic,lexerstyleconvert) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/filetree.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/filetree.lua deleted file mode 100644 index 940fed1..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/filetree.lua +++ /dev/null @@ -1,903 +0,0 @@ --- Copyright 2011-16 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide - -ide.filetree = { - projdir = "", - projdirlist = {}, - projdirpartmap = {}, - projtreeCtrl = nil, - imglist = ide:CreateImageList("PROJECT", - "FOLDER", "FILE-KNOWN", "FILE-NORMAL", "FILE-NORMAL-START", - "FOLDER-MAPPED"), - settings = {extensionignore = {}, startfile = {}, mapped = {}}, -} -local filetree = ide.filetree -local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a")) -local pathsep = GetPathSeparator() -local q = EscapeMagic -local image = { - DIRECTORY = 0, FILEKNOWN = 1, FILEOTHER = 2, FILEOTHERSTART = 3, - DIRECTORYMAPPED = 4, -} - -MergeSettings(filetree.settings, ide:AddPackage('core.filetree', {}):GetSettings()) - --- generic tree --- ------------ - -local function getIcon(name, isdir) - local startfile = GetFullPathIfExists(FileTreeGetDir(), - filetree.settings.startfile[FileTreeGetDir()]) - local known = GetSpec(GetFileExt(name)) - local icon = isdir and image.DIRECTORY or known and image.FILEKNOWN or image.FILEOTHER - if startfile and startfile == name then icon = image.FILEOTHERSTART end - return icon -end - -local function treeAddDir(tree,parent_id,rootdir) - local items = {} - local item, cookie = tree:GetFirstChild(parent_id) - while item:IsOk() do - items[tree:GetItemText(item) .. tree:GetItemImage(item)] = item - item, cookie = tree:GetNextChild(parent_id, cookie) - end - - local cache = {} - local curr - local files = FileSysGetRecursive(rootdir) - local dirmapped = {} - if tree:IsRoot(parent_id) then - local mapped = filetree.settings.mapped[FileTreeGetDir()] or {} - table.sort(mapped) - -- insert into files at the sorted order - for i, v in ipairs(mapped) do - table.insert(files, i, v) - dirmapped[v] = true - end - end - - for _, file in ipairs(files) do - local name, dir = file:match("([^"..pathsep.."]+)("..pathsep.."?)$") - local isdir = #dir>0 - if isdir or not filetree.settings.extensionignore[GetFileExt(name)] then - local icon = getIcon(file, isdir) - - -- keep full name for the mapped directories - if dirmapped[file] then name, icon = file, image.DIRECTORYMAPPED end - - local item = items[name .. icon] - if item then -- existing item - -- keep deleting items until we find item - while true do - local next = (curr - and tree:GetNextSibling(curr) - or tree:GetFirstChild(parent_id)) - if not next:IsOk() or name == tree:GetItemText(next) then - curr = next - break - end - tree:Delete(next) - end - else -- new item - curr = (curr - and tree:InsertItem(parent_id, curr, name, icon) - or tree:PrependItem(parent_id, name, icon)) - if isdir then tree:SetItemHasChildren(curr, FileDirHasContent(file)) end - end - if curr:IsOk() then cache[iscaseinsensitive and name:lower() or name] = curr end - end - end - - -- delete any leftovers (something that exists in the tree, but not on disk) - while true do - local next = (curr - and tree:GetNextSibling(curr) - or tree:GetFirstChild(parent_id)) - if not next:IsOk() then break end - tree:Delete(next) - end - - -- cache the mapping from names to tree items - if ide.wxver >= "2.9.5" then - local data = wx.wxLuaTreeItemData() - data:SetData(cache) - tree:SetItemData(parent_id, data) - end - - tree:SetItemHasChildren(parent_id, - tree:GetChildrenCount(parent_id, false) > 0) -end - -local function treeSetRoot(tree,rootdir) - tree:DeleteAllItems() - if (not wx.wxDirExists(rootdir)) then return end - - local root_id = tree:AddRoot(rootdir, image.DIRECTORY) - tree:SetItemHasChildren(root_id, true) -- make sure that the item can expand - tree:Expand(root_id) -- this will also populate the tree -end - -local function findItem(tree, match) - local node = tree:GetRootItem() - local label = tree:GetItemText(node) - - local s, e - if iscaseinsensitive then - s, e = string.find(match:lower(), label:lower(), 1, true) - else - s, e = string.find(match, label, 1, true) - end - if not s or s ~= 1 then return end - - for token in string.gmatch(string.sub(match,e+1), "[^%"..pathsep.."]+") do - local data = tree:GetItemData(node) - local cache = data and data:GetData() - if cache and cache[iscaseinsensitive and token:lower() or token] then - node = cache[iscaseinsensitive and token:lower() or token] - else - -- token is missing; may need to re-scan the folder; maybe new file - local dir = tree:GetItemFullName(node) - treeAddDir(tree,node,dir) - - local item, cookie = tree:GetFirstChild(node) - while true do - if not item:IsOk() then return end -- not found - if tree:GetItemText(item) == token then - node = item - break - end - item, cookie = tree:GetNextChild(node, cookie) - end - end - end - - -- this loop exits only when a match is found - return node -end - -local function treeSetConnectorsAndIcons(tree) - tree:AssignImageList(filetree.imglist) - - local function isIt(item, imgtype) return tree:GetItemImage(item) == imgtype end - - function tree:IsDirectory(item_id) return isIt(item_id, image.DIRECTORY) end - function tree:IsDirMapped(item_id) return isIt(item_id, image.DIRECTORYMAPPED) end - function tree:IsFileKnown(item_id) return isIt(item_id, image.FILEKNOWN) end - function tree:IsFileOther(item_id) return isIt(item_id, image.FILEOTHER) end - function tree:IsFileStart(item_id) return isIt(item_id, image.FILEOTHERSTART) end - function tree:IsRoot(item_id) return not tree:GetItemParent(item_id):IsOk() end - - function tree:FindItem(match) - return findItem(self, (wx.wxIsAbsolutePath(match) or match == '') and match - or MergeFullPath(ide:GetProject(), match)) - end - - function tree:GetItemFullName(item_id) - local tree = self - local str = tree:GetItemText(item_id) - local cur = str - - while (#cur > 0) do - item_id = tree:GetItemParent(item_id) - if not item_id:IsOk() then break end - cur = tree:GetItemText(item_id) - if cur and #cur > 0 then str = MergeFullPath(cur, str) end - end - -- as root may already include path separator, normalize the path - local fullPath = wx.wxFileName(str) - fullPath:Normalize() - return fullPath:GetFullPath() - end - - function tree:RefreshChildren(node) - node = node or tree:GetRootItem() - treeAddDir(tree,node,tree:GetItemFullName(node)) - local item, cookie = tree:GetFirstChild(node) - while true do - if not item:IsOk() then return end - if tree:IsExpanded(item) then tree:RefreshChildren(item) end - item, cookie = tree:GetNextChild(node, cookie) - end - end - - local function refreshAncestors(node) - -- when this method is called from END_EDIT, it causes infinite loop - -- on OSX (wxwidgets 2.9.5) as Delete in treeAddDir calls END_EDIT again. - -- disable handlers while the tree is populated and then enable back. - tree:SetEvtHandlerEnabled(false) - while node:IsOk() do - local dir = tree:GetItemFullName(node) - treeAddDir(tree,node,dir) - node = tree:GetItemParent(node) - end - tree:SetEvtHandlerEnabled(true) - end - - function tree:ActivateItem(item_id) - local name = tree:GetItemFullName(item_id) - - local event = wx.wxTreeEvent(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item_id:GetValue()) - if PackageEventHandle("onFiletreeActivate", tree, event, item_id) == false then - return - end - - -- refresh the folder - if (tree:IsDirectory(item_id) or tree:IsDirMapped(item_id)) then - if wx.wxDirExists(name) then treeAddDir(tree,item_id,name) - else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content - else -- open file - if wx.wxFileExists(name) then LoadFile(name,nil,true) - else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content - end - end - - local function unMapDir(dir) - local project = FileTreeGetDir() - local mapped = filetree.settings.mapped[project] or {} - for k, m in ipairs(mapped) do - if m == dir then table.remove(mapped, k) end - end - filetree.settings.mapped[project] = mapped - refreshAncestors(tree:GetRootItem()) - end - local function mapDir() - local project = FileTreeGetDir() - local dirPicker = wx.wxDirDialog(ide.frame, TR("Choose a directory to map"), - project ~= "" and project or wx.wxGetCwd(), wx.wxDIRP_DIR_MUST_EXIST) - if dirPicker:ShowModal(true) ~= wx.wxID_OK then return end - local dir = wx.wxFileName.DirName(FixDir(dirPicker:GetPath())):GetFullPath() - local mapped = filetree.settings.mapped[project] or {} - for _, m in ipairs(mapped) do - if m == dir then return end -- already on the list - end - table.insert(mapped, dir) - filetree.settings.mapped[project] = mapped - refreshAncestors(tree:GetRootItem()) - end - - local empty = "" - local function renameItem(itemsrc, target) - local cache = type(itemsrc) == 'table' and itemsrc or nil - local isdir = not cache and tree:IsDirectory(itemsrc) or cache and cache.isdir or false - local isnew = not cache and tree:GetItemText(itemsrc) == empty or cache and cache.isnew or false - local source = cache and cache.fullname or tree:GetItemFullName(itemsrc) - local fn = wx.wxFileName(target) - - -- check if the target is the same as the source; - -- SameAs check is not used here as "Test" and "test" are the same - -- on case insensitive systems, but need to be allowed in renaming. - if source == target then return end - - local docs = {} - if not isnew then -- find if source is already opened in the editor - docs = (isdir - and ide:FindDocumentsByPartialPath(source) - or {ide:FindDocument(source)}) - for _, doc in ipairs(docs) do - if not isdir and PackageEventHandle("onEditorPreSave", doc.editor, source) == false then - return false - end - if SaveModifiedDialog(doc.editor, true) == wx.wxID_CANCEL then return end - end - end - - -- check if existing file/dir is going to be overwritten - local overwrite = ((wx.wxFileExists(target) or wx.wxDirExists(target)) - and not wx.wxFileName(source):SameAs(fn)) - if overwrite and not ApproveFileOverwrite() then return false end - - if not fn:Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL) then - ReportError(TR("Unable to create directory '%s'."):format(target)) - return false - end - - if isnew then -- new directory or file; create manually - if (isdir and not wx.wxFileName.DirName(target):Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL)) - or (not isdir and not FileWrite(target, "")) then - ReportError(TR("Unable to create file '%s'."):format(target)) - return false - end - else -- existing directory or file; rename/move it - local ok, err = FileRename(source, target) - if not ok then - ReportError(TR("Unable to rename file '%s'."):format(source) - .."\nError: "..err) - return false - end - end - - refreshAncestors(cache and cache.parent or tree:GetItemParent(itemsrc)) - -- load file(s) into the same editor (if any); will also refresh the tree - if #docs > 0 then - for _, doc in ipairs(docs) do - local fullpath = doc.filePath - doc.filePath = nil -- remove path to avoid "file no longer exists" message - -- when moving folders, /foo/bar/file.lua can be replaced with - -- /foo/baz/bar/file.lua, so change /foo/bar to /foo/baz/bar - local path = (not iscaseinsensitive and fullpath:gsub(q(source), target) - or fullpath:lower():gsub(q(source:lower()), target)) - local editor = LoadFile(path) - -- check if the file was loaded into another editor; - -- this is possible if "foo" is renamed to "bar" and both are opened; - -- if this happens, then "bar" is refreshed and "foo" can be closed. - if doc.editor:GetId() ~= editor:GetId() then ClosePage(doc.index) end - if not isdir and editor then PackageEventHandle("onEditorSave", editor) end - end - else -- refresh the tree and select the new item - local itemdst = tree:FindItem(target) - if itemdst then - refreshAncestors(tree:GetItemParent(itemdst)) - tree:SelectItem(itemdst) - tree:EnsureVisible(itemdst) - tree:SetScrollPos(wx.wxHORIZONTAL, 0, true) - end - end - - -- refresh the target if it's open and has been overwritten - if overwrite and not isdir then - local doc = ide:FindDocument(target) - if doc then LoadFile(doc:GetFilePath(), doc:GetEditor()) end - end - - return true - end - local function deleteItem(item_id) - -- if delete is for mapped directory, unmap it instead - if tree:IsDirMapped(item_id) then - unMapDir(tree:GetItemText(item_id)) - return - end - - local isdir = tree:IsDirectory(item_id) - local source = tree:GetItemFullName(item_id) - - if isdir and FileDirHasContent(source..pathsep) then return false end - if wx.wxMessageBox( - TR("Do you want to delete '%s'?"):format(source), - GetIDEString("editormessage"), - wx.wxYES_NO + wx.wxCENTRE, ide.frame) ~= wx.wxYES then return false end - - if isdir then - if not wx.wxRmdir(source) then - ReportError(TR("Unable to delete directory '%s': %s") - :format(source, wx.wxSysErrorMsg())) - end - else - local doc = ide:FindDocument(source) - if doc then ClosePage(doc.index) end - if not wx.wxRemoveFile(source) then - ReportError(TR("Unable to delete file '%s': %s") - :format(source, wx.wxSysErrorMsg())) - end - end - refreshAncestors(tree:GetItemParent(item_id)) - return true - end - - tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING, - function (event) - local item_id = event:GetItem() - local dir = tree:GetItemFullName(item_id) - if wx.wxDirExists(dir) then treeAddDir(tree,item_id,dir) -- refresh folder - else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content - return true - end) - tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED, - function (event) - tree:ActivateItem(event:GetItem()) - end) - - local function saveSettings() - ide:AddPackage('core.filetree', {}):SetSettings(filetree.settings) - end - - -- refresh the tree - local function refreshChildren() - tree:RefreshChildren() - -- now mark the current file (if it was previously disabled) - local editor = ide:GetEditor() - if editor then FileTreeMarkSelected(ide:GetDocument(editor):GetFilePath()) end - end - - -- handle context menu - local function addItem(item_id, name, img) - local isdir = tree:IsDirectory(item_id) - local parent = isdir and item_id or tree:GetItemParent(item_id) - if isdir then tree:Expand(item_id) end -- expand to populate if needed - - local item = tree:PrependItem(parent, name, img) - tree:SetItemHasChildren(parent, true) - -- temporarily disable expand as we don't need this node populated - tree:SetEvtHandlerEnabled(false) - tree:EnsureVisible(item) - tree:SetEvtHandlerEnabled(true) - return item - end - - local function unsetStartFile() - local project = FileTreeGetDir() - local startfile = filetree.settings.startfile[project] - filetree.settings.startfile[project] = nil - if startfile then - local item_id = tree:FindItem(startfile) - if item_id and item_id:IsOk() then - tree:SetItemImage(item_id, getIcon(tree:GetItemFullName(item_id))) - end - end - end - - local function setStartFile(item_id) - local project = FileTreeGetDir() - local startfile = tree:GetItemFullName(item_id):gsub(project, "") - filetree.settings.startfile[project] = startfile - tree:SetItemImage(item_id, getIcon(tree:GetItemFullName(item_id))) - end - - tree:Connect(ID_NEWFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - tree:EditLabel(addItem(tree:GetSelection(), empty, image.FILEOTHER)) - end) - tree:Connect(ID_NEWDIRECTORY, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - tree:EditLabel(addItem(tree:GetSelection(), empty, image.DIRECTORY)) - end) - tree:Connect(ID_RENAMEFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() tree:EditLabel(tree:GetSelection()) end) - tree:Connect(ID_DELETEFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() deleteItem(tree:GetSelection()) end) - tree:Connect(ID_COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED, - function() ide:CopyToClipboard(tree:GetItemFullName(tree:GetSelection())) end) - tree:Connect(ID_OPENEXTENSION, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local fname = tree:GetItemFullName(tree:GetSelection()) - local ext = '.'..wx.wxFileName(fname):GetExt() - local ft = wx.wxTheMimeTypesManager:GetFileTypeFromExtension(ext) - if ft then - local cmd = ft:GetOpenCommand(fname:gsub('"','\\"')) - local pid = wx.wxExecute(cmd, wx.wxEXEC_ASYNC) - if ide.osname == 'Windows' and pid and pid > 0 then - -- some programs on Windows (for example, PhotoViewer) accept - -- files with spaces in names ONLY if they are not in quotes. - -- wait for the process that failed to open file to finish - -- and retry without quotes. - wx.wxMilliSleep(250) -- 250ms seems enough; picked empirically. - if not wx.wxProcess.Exists(pid) then - local cmd = ft:GetOpenCommand(""):gsub('""%s*$', '')..fname - wx.wxExecute(cmd, wx.wxEXEC_ASYNC) - end - end - end - end) - tree:Connect(ID_REFRESH, wx.wxEVT_COMMAND_MENU_SELECTED, - function() refreshChildren() end) - tree:Connect(ID_SHOWLOCATION, wx.wxEVT_COMMAND_MENU_SELECTED, - function() ShowLocation(tree:GetItemFullName(tree:GetSelection())) end) - tree:Connect(ID_HIDEEXTENSION, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local ext = GetFileExt(tree:GetItemText(tree:GetSelection())) - filetree.settings.extensionignore[ext] = true - saveSettings() - refreshChildren() - end) - tree:Connect(ID_SHOWEXTENSIONALL, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - filetree.settings.extensionignore = {} - saveSettings() - refreshChildren() - end) - tree:Connect(ID_SETSTARTFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - unsetStartFile() - setStartFile(tree:GetSelection()) - saveSettings() - end) - tree:Connect(ID_UNSETSTARTFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - unsetStartFile() - saveSettings() - end) - tree:Connect(ID_MAPDIRECTORY, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - mapDir() - saveSettings() - end) - tree:Connect(ID_UNMAPDIRECTORY, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - unMapDir(tree:GetItemText(tree:GetSelection())) - saveSettings() - end) - tree:Connect(ID_PROJECTDIRFROMDIR, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - ProjectUpdateProjectDir(tree:GetItemFullName(tree:GetSelection())) - end) - - tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_MENU, - function (event) - local item_id = event:GetItem() - tree:SelectItem(item_id) - - local renamelabel = (tree:IsRoot(item_id) - and TR("&Edit Project Directory") - or TR("&Rename")) - local fname = tree:GetItemText(item_id) - local ext = GetFileExt(fname) - local startfile = filetree.settings.startfile[FileTreeGetDir()] - local menu = wx.wxMenu { - { ID_NEWFILE, TR("New &File") }, - { ID_NEWDIRECTORY, TR("&New Directory") }, - { }, - { ID_RENAMEFILE, renamelabel..KSC(ID_RENAMEFILE) }, - { ID_DELETEFILE, TR("&Delete")..KSC(ID_DELETEFILE) }, - { ID_REFRESH, TR("Refresh") }, - { }, - { ID_HIDEEXTENSION, TR("Hide '.%s' Files"):format(ext) }, - { }, - { ID_SETSTARTFILE, TR("Set As Start File") }, - { ID_UNSETSTARTFILE, TR("Unset '%s' As Start File"):format(startfile or "") }, - { }, - { ID_MAPDIRECTORY, TR("Map Directory...") }, - { ID_UNMAPDIRECTORY, TR("Unmap Directory") }, - { ID_OPENEXTENSION, TR("Open With Default Program") }, - { ID_COPYFULLPATH, TR("Copy Full Path") }, - { ID_SHOWLOCATION, TR("Show Location") }, - } - local extlist = { - {}, - { ID_SHOWEXTENSIONALL, TR("Show All Files"), TR("Show all files") }, - } - for ext in pairs(filetree.settings.extensionignore) do - local id = ID("filetree.showextension."..ext) - table.insert(extlist, 1, {id, '.'..ext}) - menu:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function() - filetree.settings.extensionignore[ext] = nil - saveSettings() - refreshChildren() - end) - end - local _, _, hideextpos = ide:FindMenuItem(ID_HIDEEXTENSION, menu) - assert(hideextpos, "Can't find HideExtension menu item") - menu:Insert(hideextpos+1, wx.wxMenuItem(menu, ID_SHOWEXTENSION, - TR("Show Hidden Files"), TR("Show files previously hidden"), - wx.wxITEM_NORMAL, wx.wxMenu(extlist))) - - local projectdirectorymenu = wx.wxMenu { - { }, - {ID_PROJECTDIRCHOOSE, TR("Choose...")..KSC(ID_PROJECTDIRCHOOSE), TR("Choose a project directory")}, - {ID_PROJECTDIRFROMDIR, TR("Set To Selected Directory")..KSC(ID_PROJECTDIRFROMDIR), TR("Set project directory to the selected one")}, - } - local projectdirectory = wx.wxMenuItem(menu, ID_PROJECTDIR, - TR("Project Directory"), TR("Set the project directory to be used"), - wx.wxITEM_NORMAL, projectdirectorymenu) - local _, _, unmapdirpos = ide:FindMenuItem(ID_UNMAPDIRECTORY, menu) - assert(unmapdirpos, "Can't find UnMapDirectory menu item") - menu:Insert(unmapdirpos+1, projectdirectory) - FileTreeProjectListUpdate(projectdirectorymenu, 0) - - -- disable Delete on non-empty directories - local isdir = tree:IsDirectory(item_id) - local ismapped = tree:IsDirMapped(item_id) - menu:Destroy(ismapped and ID_MAPDIRECTORY or ID_UNMAPDIRECTORY) - if not startfile then menu:Destroy(ID_UNSETSTARTFILE) end - if ismapped then menu:Enable(ID_RENAMEFILE, false) end - if isdir then - local source = tree:GetItemFullName(item_id) - menu:Enable(ID_DELETEFILE, not FileDirHasContent(source..pathsep)) - menu:Enable(ID_OPENEXTENSION, false) - menu:Enable(ID_HIDEEXTENSION, false) - else - local ft = wx.wxTheMimeTypesManager:GetFileTypeFromExtension('.'..ext) - menu:Enable(ID_OPENEXTENSION, ft and #ft:GetOpenCommand("") > 0) - menu:Enable(ID_HIDEEXTENSION, not filetree.settings.extensionignore[ext]) - menu:Enable(ID_PROJECTDIRFROMDIR, false) - end - menu:Enable(ID_SETSTARTFILE, tree:IsFileOther(item_id) or tree:IsFileKnown(item_id)) - menu:Enable(ID_SHOWEXTENSION, next(filetree.settings.extensionignore) ~= nil) - - PackageEventHandle("onMenuFiletree", menu, tree, event) - - -- stopping/restarting garbage collection is generally not needed, - -- but on Linux not stopping is causing crashes (wxwidgets 2.9.5 and 3.1.0) - -- when symbol indexing is done while popup menu is open (with gc methods in the trace). - -- this only happens when EVT_IDLE is called when popup menu is open. - collectgarbage("stop") - - -- stopping UI updates is generally not needed as well, - -- but it's causing a crash on OSX (wxwidgets 2.9.5 and 3.1.0) - -- when symbol indexing is done while popup menu is open, so it's disabled - local interval = wx.wxUpdateUIEvent.GetUpdateInterval() - wx.wxUpdateUIEvent.SetUpdateInterval(-1) -- don't update - - tree:PopupMenu(menu) - wx.wxUpdateUIEvent.SetUpdateInterval(interval) - collectgarbage("restart") - end) - - tree:Connect(wx.wxEVT_RIGHT_DOWN, - function (event) - local item_id = tree:HitTest(event:GetPosition()) - if PackageEventHandle("onFiletreeRDown", tree, event, item_id) == false then - return - end - event:Skip() - end) - - -- toggle a folder on a single click - tree:Connect(wx.wxEVT_LEFT_DOWN, - function (event) - -- only toggle if this is a folder and the click is on the item line - -- (exclude the label as it's used for renaming and dragging) - local mask = (wx.wxTREE_HITTEST_ONITEMINDENT - + wx.wxTREE_HITTEST_ONITEMICON + wx.wxTREE_HITTEST_ONITEMRIGHT) - local item_id, flags = tree:HitTest(event:GetPosition()) - - if PackageEventHandle("onFiletreeLDown", tree, event, item_id) == false then - return - end - - if item_id and bit.band(flags, mask) > 0 then - if tree:IsDirectory(item_id) then - tree:Toggle(item_id) - tree:SelectItem(item_id) - else - local name = tree:GetItemFullName(item_id) - if wx.wxFileExists(name) then LoadFile(name,nil,true) end - end - else - event:Skip() - end - return true - end) - local parent - tree:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, - function (event) - local itemsrc = event:GetItem() - parent = tree:GetItemParent(itemsrc) - if not itemsrc:IsOk() or tree:IsDirMapped(itemsrc) then event:Veto() end - end) - tree:Connect(wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT, - function (event) - -- veto the event to keep the original label intact as the tree - -- is going to be refreshed with the correct names. - event:Veto() - - local itemsrc = event:GetItem() - if not itemsrc:IsOk() then return end - - local label = event:GetLabel():gsub("^%s+$","") -- clean all spaces - - -- edited the root element; set the new project directory if needed - local cancelled = event:IsEditCancelled() - if tree:IsRoot(itemsrc) then - if not cancelled and wx.wxDirExists(label) then - ProjectUpdateProjectDir(label) - end - return - end - - if not parent or not parent:IsOk() then return end - local target = MergeFullPath(tree:GetItemFullName(parent), label) - if cancelled or label == empty then refreshAncestors(parent) - elseif target then - -- normally, none of this caching would be needed as `renameItem` - -- would be called to check if the item can be renamed; - -- however, as it may open a dialog box, on Linux it's causing a crash - -- (caused by the same END_LABEL_EDIT even triggered one more time), - -- so to protect from that, `renameItem` is called from IDLE event. - -- Unfortunately, by that time, the filetree item (`itemsrc`) may - -- already have incorrect state (as it's removed from the tree), - -- so its properties need to be cached to be used from IDLE event. - local cache = { - isdir = tree:IsDirectory(itemsrc), - isnew = tree:GetItemText(itemsrc) == empty, - fullname = tree:GetItemFullName(itemsrc), - parent = parent, - } - ide:DoWhenIdle(function() - if not renameItem(cache, target) then refreshAncestors(parent) end - end) - end - end) - - local itemsrc - tree:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_DRAG, - function (event) - if ide.config.filetree.mousemove and tree:GetItemParent(event:GetItem()):IsOk() then - itemsrc = event:GetItem() - event:Allow() - end - end) - tree:Connect(wx.wxEVT_COMMAND_TREE_END_DRAG, - function (event) - local itemdst = event:GetItem() - if not itemdst:IsOk() or not itemsrc:IsOk() then return end - - -- check if itemdst is a folder - local target = tree:GetItemFullName(itemdst) - if wx.wxDirExists(target) then - local source = tree:GetItemFullName(itemsrc) - -- check if moving the directory and target is a subfolder of source - if (target..pathsep):find("^"..q(source)..pathsep) then return end - renameItem(itemsrc, MergeFullPath(target, tree:GetItemText(itemsrc))) - end - end) -end - --- project -local projtree = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, - wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_LINES_AT_ROOT - + wx.wxTR_EDIT_LABELS + wx.wxNO_BORDER) -projtree:SetFont(ide.font.fNormal) -filetree.projtreeCtrl = projtree - -ide:GetProjectNotebook():AddPage(projtree, TR("Project"), true) - --- proj connectors --- --------------- - -treeSetConnectorsAndIcons(projtree) - --- proj functions --- --------------- - -function filetree:updateProjectDir(newdir) - if (not newdir) or not wx.wxDirExists(newdir) then return end - local dirname = wx.wxFileName.DirName(newdir) - - if filetree.projdir and #filetree.projdir > 0 - and dirname:SameAs(wx.wxFileName.DirName(filetree.projdir)) then return end - - -- strip the last path separator if any - local newdir = dirname:GetPath(wx.wxPATH_GET_VOLUME) - - -- save the current interpreter as it may be reset in onProjectClose - -- when the project event handlers manipulates interpreters - local intfname = ide.interpreter and ide.interpreter.fname - - if filetree.projdir and #filetree.projdir > 0 then - PackageEventHandle("onProjectClose", filetree.projdir) - end - - PackageEventHandle("onProjectPreLoad", newdir) - - if ide.config.projectautoopen and filetree.projdir then - StoreRestoreProjectTabs(filetree.projdir, newdir, intfname) - end - - filetree.projdir = newdir - filetree.projdirpartmap = {} - - PrependStringToArray( - filetree.projdirlist, - newdir, - ide.config.projecthistorylength, - function(s1, s2) return dirname:SameAs(wx.wxFileName.DirName(s2)) end) - - ProjectUpdateProjectDir(newdir,true) - treeSetRoot(projtree,newdir) - - -- sync with the current editor window and activate selected file - local editor = GetEditor() - if editor then FileTreeMarkSelected(ide:GetDocument(editor):GetFilePath()) end - - -- refresh Recent Projects menu item - ide.frame:AddPendingEvent(wx.wxUpdateUIEvent(ID_RECENTPROJECTS)) - - PackageEventHandle("onProjectLoad", newdir) -end - -function FileTreeGetDir() - return (filetree.projdir and #filetree.projdir > 0 - and wx.wxFileName.DirName(filetree.projdir):GetFullPath() or nil) -end - -function FileTreeSetProjects(tab) - filetree.projdirlist = tab - if (tab and tab[1]) then - filetree:updateProjectDir(tab[1]) - end -end - -function FileTreeGetProjects() - return filetree.projdirlist -end - -local function getProjectLabels() - local labels = {} - local fmt = ide.config.format.menurecentprojects or '%f' - for _, proj in ipairs(FileTreeGetProjects()) do - local config = ide.session.projects[proj] - local intfname = config and config[2] and config[2].interpreter or ide.interpreter:GetFileName() - local interpreter = intfname and ide.interpreters[intfname] - local parts = wx.wxFileName(proj..pathsep):GetDirs() - table.insert(labels, ExpandPlaceholders(fmt, { - f = proj, - i = interpreter and interpreter:GetName() or (intfname or '')..'?', - s = parts[#parts] or '', - })) - end - return labels -end - -function FileTreeProjectListClear() - -- remove all items from the list except the current one - filetree.projdirlist = {FileTreeGetDir()} -end - -function FileTreeProjectListUpdate(menu, items) - -- protect against recent project menu not being present - if not ide:FindMenuItem(ID_RECENTPROJECTS) then return end - - local list = getProjectLabels() - for i=#list, 1, -1 do - local id = ID("file.recentprojects."..i) - local label = list[i] - if i <= items then -- this is an existing item; update the label - menu:FindItem(id):SetItemLabel(label) - else -- need to add an item - local item = wx.wxMenuItem(menu, id, label, "") - menu:Insert(items, item) - ide.frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function() - wx.wxSafeYield() -- let the menu on screen (if any) disappear - ProjectUpdateProjectDir(FileTreeGetProjects()[i]) - end) - end - -- disable the currently selected project - if i == 1 then menu:Enable(id, false) end - end - for i=items, #list+1, -1 do -- delete the rest if the list got shorter - menu:Delete(menu:FindItemByPosition(i-1)) - end - return #list -end - -local curr_file -function FileTreeMarkSelected(file) - if not file or not filetree.projdir or #filetree.projdir == 0 then return end - - local item_id = wx.wxIsAbsolutePath(file) and projtree:FindItem(file) - - -- if the select item is different from the current one - -- or the current one is the same, but not bold (which may happen when - -- the project is changed to one that includes the current item) - if curr_file ~= file - or item_id and not projtree:IsBold(item_id) then - if curr_file then - local curr_id = wx.wxIsAbsolutePath(curr_file) and projtree:FindItem(curr_file) - if curr_id and projtree:IsBold(curr_id) then - projtree:SetItemBold(curr_id, false) - end - end - if item_id then - projtree:EnsureVisible(item_id) - projtree:SetScrollPos(wx.wxHORIZONTAL, 0, true) - projtree:SetItemBold(item_id, true) - end - curr_file = file - if ide.wxver < "2.9.5" and ide.osname == 'Macintosh' then - projtree:Refresh() - end - end -end - -function FileTreeFindByPartialName(name) - -- check if it's already cached - if filetree.projdirpartmap[name] then return filetree.projdirpartmap[name] end - - -- this function may get a partial name that starts with ... and has - -- an abbreviated path (as generated by stack traces); - -- remove starting "..." if any and escape - local pattern = q(name:gsub("^%.%.%.","")):gsub("[\\/]", "[\\/]").."$" - local lpattern = pattern:lower() - - for _, file in ipairs(FileSysGetRecursive(filetree.projdir, true)) do - if file:find(pattern) or iscaseinsensitive and file:lower():find(lpattern) then - filetree.projdirpartmap[name] = file - return file - end - end - return -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/findreplace.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/findreplace.lua deleted file mode 100644 index 3159585..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/findreplace.lua +++ /dev/null @@ -1,1275 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local searchpanel = 'searchpanel' -local q = EscapeMagic -local unpack = table.unpack or unpack -ide.findReplace = { - panel = nil, -- the control for find/replace - replace = false, -- is it a find or replace - infiles = false, - backfocus = nil, -- editor and position to return focus to - cureditor = nil, -- the editor being searched - reseditor = nil, -- the editor for search results - oveditor = nil, -- the editor is used for search during find-in-files - findCtrl = nil, -- the control that has the search text - replaceCtrl = nil, -- the control that has the replace text - scopeText = nil, - foundString = false, -- was the string found for the last search - curfilename = "", -- for search in files - inselection = false, - occurrences = 0, - files = 0, - - settings = { - flags = { - WholeWord = false, -- match whole words - MatchCase = false, -- case sensitive - RegularExpr = false, -- use regex - Wrap = true, -- search wraps around - Down = true, -- search downwards in doc - Context = true, -- include context in search results - SubDirs = true, -- search in subdirectories - MultiResults = false, -- show multiple result tabs - }, - flist = {}, - rlist = {}, - slist = {}, - }, - - -- HasText() is there a string to search for - -- GetSelection() get currently selected string if it's on one line - -- Find(reverse) find the text - -- Show(replace) create the dialog - -- GetEditor() which editor to use -} -local findReplace = ide.findReplace -local NOTFOUND = -1 -local replaceHintText = '' -local sep = ';' - -function findReplace:GetEditor(reset) - if reset or not ide:IsValidCtrl(self.cureditor) then self.cureditor = nil end - self.cureditor = ide:GetEditorWithLastFocus() or self.cureditor - return self.oveditor or self.cureditor or GetEditor() -end - --------------------- Find replace dialog - -local function setSearchFlags(editor) - local flags = wxstc.wxSTC_FIND_POSIX - local f = findReplace.settings.flags - if f.WholeWord then flags = flags + wxstc.wxSTC_FIND_WHOLEWORD end - if f.MatchCase then flags = flags + wxstc.wxSTC_FIND_MATCHCASE end - if f.RegularExpr then flags = flags + wxstc.wxSTC_FIND_REGEXP end - editor:SetSearchFlags(flags) -end - -local function setTarget(editor, flags) - flags = flags or {} - local fDown, fAll, fWrap = flags.Down, flags.All, flags.Wrap - local len = editor:GetLength() - local selStart, selEnd = editor:GetSelectionStart(), editor:GetSelectionEnd() - local s, e - if fDown then - e = flags.EndPos or len - s = math.min(e, math.max(flags.StartPos or 0, iff(fAll, selStart, selEnd))) - else -- reverse the range for the backward search - e = flags.StartPos or 0 - s = math.max(e, math.min(flags.EndPos or len, iff(fAll, selEnd, selStart))) - end - -- if wrap around and search all requested, then search the entire document - if fAll and fWrap then s, e = 0, len end - editor:SetTargetStart(s) - editor:SetTargetEnd(e) - return e -end - -function findReplace:IsPreview(editor) - local ok, ispreview = pcall(function() return editor and editor.searchpreview end) - return ok and ispreview and true or false -end - -function findReplace:CanSave(editor) - return editor and editor:GetModify() and self:IsPreview(editor) and editor or nil -end - -function findReplace:HasText() - if not self.panel then self:createPanel() end - local findText = self.findCtrl:GetValue() - return findText ~= nil and #findText > 0 and findText or nil -end - -function findReplace:SetStatus(msg) - if self.status then self.status:SetLabel(msg) end -end - -function findReplace:SetFind(text) - if not self.panel then self:createPanel() end - local ctrl = self.findCtrl - if text and ctrl then - if ctrl:GetValue() ~= text then ctrl:ChangeValue(text) end - return text - end - return -end - -function findReplace:GetFind(...) return self:HasText() end - -function findReplace:GetFlags() return self.settings.flags end - -function findReplace:SetReplace(text) - if not self.panel then self:createPanel() end - local ctrl = self.replaceCtrl - if text and ctrl then - if ctrl:GetValue() ~= text then ctrl:ChangeValue(text) end - return text - end - return -end - -function findReplace:GetScope() - local scopeval = self.scope:GetValue() - local dir, mask = scopeval:match(('([^%s]*)%s%%s*(.+)'):format(sep,sep)) - if not dir then dir = scopeval end - -- trip leading/trailing spaces from the directory - dir = dir:gsub("^%s+",""):gsub("%s+$","") - -- if the directory doesn't exist, treat it as the extension(s) - if not mask and not wx.wxDirExists(dir) and dir:find('%*') then - dir, mask = ide:GetProject() or wx.wxGetCwd(), (#dir > 0 and dir or nil) - end - return dir, mask -end - -function findReplace:SetScope(dir, mask) - return dir .. (mask and (sep..' '..mask) or "") -end - -function findReplace:GetScopeMRU(head) - local patt, match = "^"..q(head) - for _, v in ipairs(findReplace.settings.slist) do - if v:find(patt) then match = v; break end - end - return match -end - -function findReplace:GetWordAtCaret() - local editor = self:GetEditor() - if editor then - local pos = editor:GetCurrentPos() - local text = editor:GetTextRangeDyn( -- try to select a word under caret - editor:WordStartPosition(pos, true), editor:WordEndPosition(pos, true)) - if #text == 0 then - editor:GetTextRangeDyn( -- try to select a non-word under caret - editor:WordStartPosition(pos, false), editor:WordEndPosition(pos, false)) - end - return #text > 0 and text or nil - end - return -end - -function findReplace:GetSelection() - local editor = self:GetEditor() - if editor then - local startSel = editor:GetSelectionStart() - local endSel = editor:GetSelectionEnd() - if (startSel ~= endSel) - and (editor:LineFromPosition(startSel) == editor:LineFromPosition(endSel)) then - return editor:GetTextRangeDyn(startSel, endSel) - end - end - return -end - -function findReplace:Find(reverse) - if not self.panel then self:createPanel() end - local findText = self.findCtrl:GetValue() - - local msg = "" - local editor = self:GetEditor() - if editor and self:HasText() then - local fDown = iff(reverse, not self:GetFlags().Down, self:GetFlags().Down) - local bf = self.inselection and self.backfocus or {} - setSearchFlags(editor) - setTarget(editor, {Down = fDown, StartPos = bf.spos, EndPos = bf.epos}) - local posFind = editor:SearchInTarget(findText) - if (posFind == NOTFOUND) and self:GetFlags().Wrap then - editor:SetTargetStart(iff(fDown, bf.spos or 0, bf.epos or editor:GetLength())) - editor:SetTargetEnd(iff(fDown, bf.epos or editor:GetLength(), bf.spos or 0)) - posFind = editor:SearchInTarget(findText) - msg = (self.inselection - and TR("Reached end of selection and wrapped around.") - or TR("Reached end of text and wrapped around.") - ) - end - if posFind == NOTFOUND then - self.foundString = false - msg = TR("Text not found.") - else - self.foundString = true - local start = editor:GetTargetStart() - local finish = editor:GetTargetEnd() - editor:ShowPosEnforcePolicy(finish) - editor:SetSelection(start, finish) - end - end - self:SetStatus(msg) - return self.foundString -end - --- returns true if something was found --- [inFileRegister(pos)] passing function will --- register every position item was found - -function findReplace:FindAll(inFileRegister) - if not self.panel then self:createPanel() end - local findText = self.findCtrl:GetValue() - - local found = false - local editor = self:GetEditor() - if editor and self:HasText() then - local e = setTarget(editor, {All = true, Wrap = true}) - - setSearchFlags(editor) - while true do - local posFind = editor:SearchInTarget(findText) - if posFind == NOTFOUND then break end - inFileRegister(posFind, editor:GetTargetEnd()-posFind) - editor:SetTargetStart(editor:GetTargetEnd()) - editor:SetTargetEnd(e) - found = true - end - if inFileRegister and found then inFileRegister() end - end - - return found -end - -local indicator = { - SEARCHMATCH = ide:GetIndicator("core.searchmatch"), -} - --- returns true if replacements were done -function findReplace:Replace(fReplaceAll, resultsEditor) - if not self.panel then self:createPanel() end - - local findText = self.findCtrl:GetValue() - local replaceText = self.replaceCtrl:GetValue() - if replaceText == replaceHintText then replaceText = "" end - - local replaced = false - local editor = resultsEditor or self:GetEditor() - if editor and self:HasText() then - -- don't replace in read-only editors - if editor:GetReadOnly() then - self:SetStatus(TR("Can't replace in read-only text.")) - return false - end - - -- in the preview results always replace in the entire file - local bf = self.inselection and self.backfocus - local endTarget = (resultsEditor and setTarget(editor, {All = true, Wrap = true}) - -- when selection is marked, only replace in the selection - or (bf and setTarget(editor, {Down = self:GetFlags().Down, All = fReplaceAll, StartPos = bf.spos, EndPos = bf.epos})) - -- in all other cases, replace as selected - or setTarget(editor, {Down = self:GetFlags().Down, All = fReplaceAll, Wrap = self:GetFlags().Wrap}) - ) - - if fReplaceAll then - if resultsEditor then editor:SetIndicatorCurrent(indicator.SEARCHMATCH) end - - setSearchFlags(editor) - local occurrences = 0 - local posFind = editor:SearchInTarget(findText) - if posFind ~= NOTFOUND then - editor:BeginUndoAction() - while posFind ~= NOTFOUND do - local length = editor:GetLength() - -- if replace-in-files (resultsEditor) is being done, - -- then check that the match starts with %d+: - local match = true - if resultsEditor then - local line = editor:LineFromPosition(posFind) - local _, _, prefix = editor:GetLineDyn(line):find("^(%s*%d+: )") - match = prefix and posFind >= editor:PositionFromLine(line)+#prefix - end - if match then - local replaced = self:GetFlags().RegularExpr - and editor:ReplaceTargetRE(replaceText) - or editor:ReplaceTarget(replaceText) - - -- mark replaced text - if resultsEditor then editor:IndicatorFillRange(posFind, replaced) end - occurrences = occurrences + 1 - end - - editor:SetTargetStart(editor:GetTargetEnd()) - -- adjust the endTarget as the position could have changed; - -- can't simply subtract text length as it could be a regexp - local adjusted = editor:GetLength() - length - endTarget = endTarget + adjusted - -- also adjust the selection as the end marker can move after replacement - if bf and bf.epos then bf.epos = bf.epos + adjusted end - editor:SetTargetEnd(endTarget) - posFind = editor:SearchInTarget(findText) - end - editor:EndUndoAction() - replaced = true - end - self:SetStatus( - TR("Replaced %d instance.", occurrences):format(occurrences)) - else - editor:TargetFromSelection() - -- check if there is anything selected as well as the user can - -- move the cursor after successful search - if editor:GetSelectionStart() ~= editor:GetSelectionEnd() - -- check that the current selection matches what's being searched for - and editor:SearchInTarget(findText) ~= NOTFOUND then - local length = editor:GetLength() - local start = editor:GetSelectionStart() - local replaced = self:GetFlags().RegularExpr - and editor:ReplaceTargetRE(replaceText) - or editor:ReplaceTarget(replaceText) - local adjusted = editor:GetLength() - length - if bf and bf.epos then bf.epos = bf.epos + adjusted end - - editor:SetSelection(start, start + replaced) - self.foundString = false - - replaced = true - end - self:Find() - end - end - - return replaced -end - -local oldline -local FILE_MARKER = ide:GetMarker("searchmatchfile") -local FILE_MARKER_VALUE = 2^FILE_MARKER -local function getRawLine(ed, line) return (ed:GetLineDyn(line):gsub("[\n\r]+$","")) end -local function onFileRegister(pos, length) - local editor = findReplace.oveditor - local reseditor = findReplace.reseditor - local posline = pos and editor:LineFromPosition(pos) + 1 - local text = "" - local cfg = ide.config.search - local contextb = findReplace:GetFlags().Context and cfg.contextlinesbefore or 0 - local contexta = findReplace:GetFlags().Context and cfg.contextlinesafter or 0 - local lines = reseditor:GetLineCount() -- current number of lines - - -- check if there is another match on the same line; do not add anything - if oldline ~= posline then - if posline and not oldline then - -- show file name and a bookmark marker - reseditor:AppendTextDyn(findReplace.curfilename.."\n") - reseditor:MarkerAdd(lines-1, FILE_MARKER) - reseditor:SetFoldLevel(lines-1, reseditor:GetFoldLevel(lines-1) - + wxstc.wxSTC_FOLDLEVELHEADERFLAG) - findReplace:SetStatus(GetFileName(findReplace.curfilename)) - - lines = lines + 1 - - -- show context lines before posline - for line = math.max(1, posline-contextb), posline-1 do - text = text .. ("%5d %s\n"):format(line, getRawLine(editor, line-1)) - end - end - if posline and oldline then - -- show context lines between oldposline and posline - for line = oldline+1, math.min(posline-1, oldline+contexta) do - text = text .. ("%5d %s\n"):format(line, getRawLine(editor, line-1)) - end - if contextb + contexta > 0 and posline-oldline > contextb + contexta + 1 then - text = text .. ("%5s\n"):format(("."):rep(#tostring(posline))) - end - for line = math.max(oldline+contexta+1, posline-contextb), posline-1 do - text = text .. ("%5d %s\n"):format(line, getRawLine(editor, line-1)) - end - end - if posline then - text = text .. ("%5d: %s\n"):format(posline, getRawLine(editor, posline-1)) - findReplace.lines = findReplace.lines + 1 - elseif oldline then - -- show context lines after posline - for line = oldline+1, math.min(editor:GetLineCount(), oldline+contexta) do - text = text .. ("%5d %s\n"):format(line, getRawLine(editor, line-1)) - end - text = text .. "\n" - end - oldline = posline - - reseditor:AppendTextDyn(text) - - for line = lines-1, reseditor:GetLineCount()-2 do - reseditor:SetFoldLevel(line, wxstc.wxSTC_FOLDLEVELBASE + 1) - end - end - - if posline then - findReplace.occurrences = findReplace.occurrences + 1 - - -- get the added line - local markline = reseditor:GetLineCount()-2 - -- get the match position in the file relative to the beginning of the line - local localpos = pos - editor:PositionFromLine(posline-1) - -- recalculate position in the search results relative to the line - local newpos = reseditor:PositionFromLine(markline)+localpos+7 -- add indent - reseditor:SetIndicatorCurrent(indicator.SEARCHMATCH) - reseditor:IndicatorFillRange(newpos, length) - end -end - -local firstReadSize = 2048 -local knownBinary = {} -local function checkBinary(ext, content) - if not content then return knownBinary[ext] end - if ext == "" then return IsBinary(content) end - if knownBinary[ext] == nil then knownBinary[ext] = IsBinary(content) end - return knownBinary[ext] -end - -function findReplace:ProcInFiles(startdir,mask,subdirs) - if not self.panel then self:createPanel() end - - local text = not self:GetFlags().RegularExpr and q(self.findCtrl:GetValue()) or nil - if text and not self:GetFlags().MatchCase then - text = text:gsub("%w",function(s) return "["..s:lower()..s:upper().."]" end) - end - - local files = coroutine.wrap(function() FileSysGetRecursive(startdir, subdirs, mask, {yield = true, folder = false}) end) - while true do - local file = files() - if not file then break end - - if checkBinary(GetFileExt(file)) ~= true then - self.curfilename = file - local filetext, err = FileRead(file, firstReadSize) - if not filetext then - DisplayOutputLn(TR("Can't open file '%s': %s"):format(file, err)) - elseif not checkBinary(GetFileExt(file), filetext) then - -- read the rest if there is more to read in the file - if #filetext == firstReadSize then filetext = FileRead(file) end - if filetext and (not text or filetext:find(text)) then - self.oveditor:SetTextDyn(filetext) - - if self:FindAll(onFileRegister) then self.files = self.files + 1 end - - -- give time to the UI to refresh - ide:Yield() - -- the IDE may be quitting after Yield or the tab may be closed, - local ok, mgr = pcall(function() return ide:GetUIManager() end) - -- so check to make sure the manager is still active - if not (ok and mgr:GetPane(searchpanel):IsShown()) - -- and check that the search results tab is still open - or not ide:IsValidCtrl(self.reseditor) then - return false - end - end - end - end - end - return true -end - -local function makePlural(word, counter) return word..(counter == 1 and '' or 's') end - -function findReplace:RunInFiles(replace) - if not self.panel then self:createPanel() end - if not self:HasText() or self.oveditor then return end - - self.oveditor = ide:CreateStyledTextCtrl(self.panel, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(0,0), wx.wxBORDER_NONE) - self.occurrences = 0 - self.lines = 0 - self.files = 0 - self.toolbar:UpdateWindowUI(wx.wxUPDATE_UI_FROMIDLE) - ide:Yield() -- let the update of the UI happen - - -- save focus to restore after adding a page with search results - local ctrl = ide:GetMainFrame():FindFocus() - local findText = self.findCtrl:GetValue() - local flags = self:GetFlags() - local showaseditor = ide.config.search.showaseditor - local nb = ide:GetOutputNotebook() - local reseditor = self.reseditor - local resultsText = "Search Results" - local previewText = resultsText..": " - local valid = self:IsPreview(reseditor) - -- open new tab if the current one is not valid - -- or if multiple tabs are requested, but when searching for different text - if not valid or (flags.MultiResults and reseditor.searchpreview ~= findText) then - -- enable folds in the preview even if disabled in the editor - local fold = ide.config.editor.fold - ide.config.editor.fold = true - if showaseditor then - reseditor = NewFile(resultsText) - else - reseditor = ide:CreateBareEditor() - reseditor:SetupKeywords("") - - local modpref = ide.MODPREF - local function setModified(modified) - local index = nb:GetPageIndex(reseditor) - local text = nb:GetPageText(index):gsub("^"..q(modpref), "") - nb:SetPageText(index, (modified and modpref or '')..text) - end - reseditor:Connect(wxstc.wxEVT_STC_SAVEPOINTREACHED, - function () setModified(false) end) - reseditor:Connect(wxstc.wxEVT_STC_SAVEPOINTLEFT, - function () setModified(true) end) - reseditor:Connect(wxstc.wxEVT_STC_MARGINCLICK, - function (event) - local editor = event:GetEventObject():DynamicCast('wxStyledTextCtrl') - local line = editor:LineFromPosition(event:GetPosition()) - local header = bit.band(editor:GetFoldLevel(line), - wxstc.wxSTC_FOLDLEVELHEADERFLAG) == wxstc.wxSTC_FOLDLEVELHEADERFLAG - if wx.wxGetKeyState(wx.WXK_SHIFT) and wx.wxGetKeyState(wx.WXK_CONTROL) then - editor:FoldSome() - elseif header then - editor:ToggleFold(line) - end - end) - - -- mark as searchpreview to allow AddPage to add "close" button - reseditor.searchpreview = findText - nb:AddPage(reseditor, previewText, true) - end - reseditor:SetWrapMode(wxstc.wxSTC_WRAP_NONE) - reseditor:SetIndentationGuides(false) - if tonumber(ide.config.search.zoom) then - reseditor:SetZoom(tonumber(ide.config.search.zoom)) - end - for m = 0, ide.MAXMARGIN do -- hide all margins except folding - if reseditor:GetMarginWidth(m) > 0 - and reseditor:GetMarginMask(m) ~= wxstc.wxSTC_MASK_FOLDERS then - reseditor:SetMarginWidth(m, 0) - end - end - reseditor:MarkerDefine(ide:GetMarker("searchmatchfile")) - reseditor:Connect(wx.wxEVT_LEFT_DCLICK, function(event) - if not wx.wxGetKeyState(wx.WXK_SHIFT) - and not wx.wxGetKeyState(wx.WXK_CONTROL) - and not wx.wxGetKeyState(wx.WXK_ALT) then - local point = event:GetPosition() - local margin = 0 - for m = 0, ide.MAXMARGIN do margin = margin + reseditor:GetMarginWidth(m) end - if point:GetX() <= margin then return end - - local pos = reseditor:PositionFromPoint(point) - local line = reseditor:LineFromPosition(pos) - local text = reseditor:GetLineDyn(line):gsub("[\n\r]+$","") - -- get line with the line number - local jumpline = text:match("^%s*(%d+)") - local file - if jumpline then - -- search back to find the file name - for curline = line-1, 0, -1 do - local text = reseditor:GetLineDyn(curline):gsub("[\n\r]+$","") - if not text:find("^%s") and wx.wxFileExists(text) then - file = text - break - end - end - else - file = text - jumpline = 1 - end - - -- activate the file and the line number - local editor = file and LoadFile(file,nil,true) - if editor then - editor:GotoLine(jumpline-1) - editor:EnsureVisibleEnforcePolicy(jumpline-1) - editor:SetFocus() - end - return - end - - event:Skip() - end) - - ide.config.editor.fold = fold - self.reseditor = reseditor - else - if showaseditor then - ide:GetDocument(reseditor):SetActive() - else - local index = nb:GetPageIndex(reseditor) - if nb:GetSelection() ~= index then nb:SetSelection(index) end - end - end - reseditor.replace = replace -- keep track of the current status - reseditor:ShowLines(0, reseditor:GetLineCount()-1) - reseditor:SetReadOnly(false) - reseditor:SetTextDyn('') - do -- update the preview name - local nb = showaseditor and ide:GetEditorNotebook() or nb - nb:SetPageText(nb:GetPageIndex(reseditor), previewText .. findText) - end - if not showaseditor and nb then -- show the bottom notebook if hidden - local uimgr = ide:GetUIManager() - if not uimgr:GetPane(nb):IsShown() then - uimgr:GetPane(nb):Show(true) - uimgr:Update() - end - end - - self:SetStatus(TR("Searching for '%s'."):format(findText)) - wx.wxSafeYield() -- allow the status to update - - local startdir, mask = self:GetScope() - local completed = self:ProcInFiles(startdir, mask or "*", flags.SubDirs) - - -- reseditor may already be closed, so check if it's valid first - if ide:IsValidCtrl(reseditor) then - reseditor:GotoPos(reseditor:GetLength()) - reseditor:AppendTextDyn(("Searched for '%s'. "):format(findText)) - if not completed then reseditor:AppendTextDyn("Cancelled by the user. ") end - reseditor:AppendTextDyn(("Found %d %s on %d %s in %d %s.") - :format( - self.occurrences, makePlural("instance", self.occurrences), - self.lines, makePlural("line", self.lines), - self.files, makePlural("file", self.files))) - reseditor:EmptyUndoBuffer() -- don't undo the changes in the results - reseditor:SetSavePoint() -- set unmodified status - - if completed and replace and self.occurrences > 0 then - reseditor:AppendTextDyn("\n\n" - .."Review the changes and save this preview to apply them.\n" - .."You can also make other changes; only lines with : will be updated.\n" - .."Context lines (if any) are used as safety checks during the update.") - self:Replace(true, reseditor) - else - reseditor:SetReadOnly(true) - end - reseditor:EnsureVisibleEnforcePolicy(reseditor:GetLineCount()-1) - reseditor.searchpreview = findText - end - - self:SetStatus(not completed and TR("Cancelled by the user.") - or TR("Found %d instance.", self.occurrences):format(self.occurrences)) - self.oveditor:Destroy() - self.oveditor = nil - self.toolbar:UpdateWindowUI(wx.wxUPDATE_UI_FROMIDLE) - - -- return focus to the control that had it if it's on the search panel - -- (as it could be changed by added results tab) - if ctrl and (ctrl:GetParent():GetId() == self.panel:GetId() or not showaseditor) then - -- set the focus temporarily on the search results tab as this provides a workaround - -- for the cursor disappearing in Search/Replace controls after results shown - -- in the same tab (somehow caused by `oveditor:Destroy()` call). - if ide:IsValidCtrl(reseditor) then reseditor:SetFocus() end - ctrl:SetFocus() - end - - if completed and ide.config.search.autohide then self:Hide() end -end - -local icons = { - find = { - internal = { - ID_FINDNEXT, ID_SEPARATOR, - ID_FINDOPTDIRECTION, ID_FINDOPTWRAPWROUND, ID_FINDOPTSELECTION, - ID_FINDOPTWORD, ID_FINDOPTCASE, ID_FINDOPTREGEX, - ID_SEPARATOR, ID_FINDOPTSTATUS, - }, - infiles = { - ID_FINDNEXT, ID_SEPARATOR, - ID_FINDOPTCONTEXT, ID_FINDOPTMULTIRESULTS, ID_FINDOPTWORD, - ID_FINDOPTCASE, ID_FINDOPTREGEX, ID_FINDOPTSUBDIR, - ID_FINDOPTSCOPE, ID_FINDSETDIR, - ID_SEPARATOR, ID_FINDOPTSTATUS, - }, - }, - replace = { - internal = { - ID_FINDNEXT, ID_FINDREPLACENEXT, ID_FINDREPLACEALL, ID_SEPARATOR, - ID_FINDOPTDIRECTION, ID_FINDOPTWRAPWROUND, ID_FINDOPTSELECTION, - ID_FINDOPTWORD, ID_FINDOPTCASE, ID_FINDOPTREGEX, - ID_SEPARATOR, ID_FINDOPTSTATUS, - }, - infiles = { - ID_FINDNEXT, ID_FINDREPLACEALL, ID_SEPARATOR, - ID_FINDOPTCONTEXT, ID_FINDOPTMULTIRESULTS, ID_FINDOPTWORD, - ID_FINDOPTCASE, ID_FINDOPTREGEX, ID_FINDOPTSUBDIR, - ID_FINDOPTSCOPE, ID_FINDSETDIR, - ID_SEPARATOR, ID_FINDOPTSTATUS, - }, - }, -} - -function findReplace:createToolbar() - local ctrl, tb, scope, status = - self.panel, self.toolbar, self.scope, self.status - local icons = icons[self.replace and "replace" or "find"][self.infiles and "infiles" or "internal"] - - local toolBmpSize = wx.wxSize(16, 16) - tb:Freeze() - tb:Clear() - for _, id in ipairs(icons) do - if id == ID_SEPARATOR then - tb:AddSeparator() - elseif id == ID_FINDOPTSCOPE then - tb:AddControl(scope) - elseif id == ID_FINDOPTSTATUS then - tb:AddControl(status) - else - local iconmap = ide.config.toolbar.iconmap[id] - if iconmap then - local icon, description = unpack(iconmap) - local isbitmap = type(icon) == "userdata" and icon:GetClassInfo():GetClassName() == "wxBitmap" - local bitmap = isbitmap and icon or ide:GetBitmap(icon, "TOOLBAR", toolBmpSize) - tb:AddTool(id, "", bitmap, (TR)(description)) - end - end - end - - local options = { - [ID_FINDOPTDIRECTION] = 'Down', - [ID_FINDOPTWRAPWROUND] = 'Wrap', - [ID_FINDOPTWORD] = 'WholeWord', - [ID_FINDOPTCASE] = 'MatchCase', - [ID_FINDOPTREGEX] = 'RegularExpr', - [ID_FINDOPTSUBDIR] = 'SubDirs', - [ID_FINDOPTCONTEXT] = 'Context', - [ID_FINDOPTMULTIRESULTS] = 'MultiResults', - } - - for id, var in pairs(options) do - local tool = tb:FindTool(id) - if tool then - local flags = self:GetFlags() - tool:SetSticky(flags[var]) - ctrl:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - flags[var] = not flags[var] - self:SaveSettings() - - tb:FindTool(id):SetSticky(flags[var]) - tb:Refresh() - end) - end - end - - local optseltool = tb:FindTool(ID_FINDOPTSELECTION) - if optseltool then - optseltool:SetSticky(self.inselection) - tb:EnableTool(ID_FINDOPTSELECTION, self.inselection) - ctrl:Connect(ID_FINDOPTSELECTION, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - self.inselection = not self.inselection - tb:FindTool(event:GetId()):SetSticky(self.inselection) - tb:Refresh() - end) - end - - tb:SetToolDropDown(ID_FINDSETDIR, true) - tb:Connect(ID_FINDSETDIR, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event) - if event:IsDropDownClicked() then - local menu = wx.wxMenu() - local pos = tb:GetToolRect(event:GetId()):GetBottomLeft() - menu:Append(ID_FINDSETDIR, TR("Choose...")) - menu:Append(ID_FINDSETTOPROJDIR, TR("Set To Project Directory")) - menu:Enable(ID_FINDSETTOPROJDIR, ide:GetProject() ~= nil) - menu:Connect(ID_FINDSETTOPROJDIR, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local _, mask = self:GetScope() - self:refreshToolbar(self:SetScope(ide:GetProject(), mask)) - end) - if #self.settings.slist > 0 then menu:AppendSeparator() end - for i, text in ipairs(self.settings.slist) do - local id = ID("findreplace.scope."..i) - menu:Append(id, text) - menu:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function() self:refreshToolbar(text) end) - end - menu:AppendSeparator() - menu:Append(ID_RECENTSCOPECLEAR, TR("Clear Items")) - menu:Enable(ID_RECENTSCOPECLEAR, #self.settings.slist > 0) - menu:Connect(ID_RECENTSCOPECLEAR, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - self.settings.slist = {} - self:SaveSettings() - end) - tb:PopupMenu(menu, pos) - else - event:Skip() - end - end) - - tb:Realize() - tb:Thaw() - - local sizer = ctrl:GetSizer() - if sizer then sizer:Layout() end -end - -function findReplace:refreshToolbar(value) - local scope = self.scope - value = value or self.scope:GetValue() - self.scope:SetMinSize(wx.wxSize(scope:GetTextExtent(value..'AZ'), -1)) - self:createToolbar() - self.scope:SetValue(value) -end - -function findReplace:createPanel() - local ctrl = wx.wxPanel(ide:GetMainFrame(), wx.wxID_ANY, wx.wxDefaultPosition, - wx.wxDefaultSize, wx.wxFULL_REPAINT_ON_RESIZE) - local mgr = ide:GetUIManager() - mgr:AddPane(ctrl, wxaui.wxAuiPaneInfo() - :Name(searchpanel):CaptionVisible(false):PaneBorder(false):Hide()) - mgr:Update() - - local tb = wxaui.wxAuiToolBar(ctrl, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, wxaui.wxAUI_TB_PLAIN_BACKGROUND) - local status = wx.wxStaticText(tb, wx.wxID_ANY, "") - local scope = wx.wxTextCtrl(tb, wx.wxID_ANY, "", - wx.wxDefaultPosition, wx.wxDefaultSize, - wx.wxTE_PROCESS_ENTER + wx.wxTE_PROCESS_TAB + wx.wxBORDER_STATIC) - -- limit the scope control height as it gets too large on Linux - scope:SetMaxSize(wx.wxSize(-1, 22)) - - self.panel = ctrl - self.status = status - self.toolbar = tb - self.scope = scope - - self:createToolbar() - - local style, styledef = ide.config.styles, StylesGetDefault() - local textcolor = wx.wxColour(unpack(style.text.fg or styledef.text.fg)) - local backcolor = wx.wxColour(unpack(style.text.bg or styledef.text.bg)) - local pancolor = tb:GetBackgroundColour() - local borcolor = ide:GetUIManager():GetArtProvider():GetColor(wxaui.wxAUI_DOCKART_BORDER_COLOUR) - local bpen = wx.wxPen(borcolor, 1, wx.wxSOLID) - local bbrush = wx.wxBrush(pancolor, wx.wxSOLID) - local tfont = ide:GetProjectTree():GetFont() - -- don't increase font size on Linux as it gets too large - tfont:SetPointSize(tfont:GetPointSize() + (ide.osname == 'Unix' and 0 or 1)) - - local findCtrl = wx.wxTextCtrl(ctrl, wx.wxID_ANY, "", - wx.wxDefaultPosition, wx.wxDefaultSize, - wx.wxTE_PROCESS_ENTER + wx.wxTE_PROCESS_TAB + wx.wxBORDER_STATIC) - local replaceCtrl = wx.wxTextCtrl(ctrl, wx.wxID_ANY, replaceHintText, - wx.wxDefaultPosition, wx.wxDefaultSize, - wx.wxTE_PROCESS_ENTER + wx.wxTE_PROCESS_TAB + wx.wxBORDER_STATIC) - self.ac = {[findCtrl:GetId()] = {}, [replaceCtrl:GetId()] = {}, [scope:GetId()] = {}} - - local findSizer = wx.wxBoxSizer(wx.wxHORIZONTAL) - findSizer:Add(findCtrl, 1, wx.wxLEFT + wx.wxRIGHT + wx.wxALIGN_LEFT + wx.wxEXPAND + wx.wxFIXED_MINSIZE, 1) - findSizer:Add(replaceCtrl, 1, wx.wxLEFT + wx.wxRIGHT + wx.wxALIGN_LEFT + wx.wxEXPAND + wx.wxFIXED_MINSIZE, 1) - findSizer:Hide(1) - - local mainSizer = wx.wxBoxSizer(wx.wxVERTICAL) - mainSizer:Add(tb, 0, wx.wxTOP + wx.wxLEFT + wx.wxRIGHT + wx.wxALIGN_LEFT + wx.wxEXPAND, 2) - mainSizer:Add(findSizer, 0, wx.wxALL + wx.wxALIGN_LEFT + wx.wxEXPAND, 2) - - ctrl:SetSizer(mainSizer) - ctrl:GetSizer():Fit(ctrl) - - for _, control in ipairs({findCtrl, replaceCtrl}) do - control:SetBackgroundColour(backcolor) - control:SetForegroundColour(textcolor) - control:SetFont(tfont) - end - scope:SetBackgroundColour(pancolor) -- set toolbar background - scope:SetFont(tfont) - status:SetFont(tfont) - - local function updateLists() - PrependStringToArray(self.settings.flist, findCtrl:GetValue()) - if self.replace then - local replaceText = replaceCtrl:GetValue() - if replaceText == replaceHintText then replaceText = "" end - PrependStringToArray(self.settings.rlist, replaceText) - end - if self.infiles then - PrependStringToArray(self.settings.slist, self.scope:GetValue()) - end - self:SaveSettings() - return true - end - - local function findNext() - updateLists() - if findReplace.infiles then - findReplace:RunInFiles(false) - else - findReplace:Find() - end - end - - local function autoComplete(event) - if not ide.config.search.autocomplete then return end - - local obj = event:GetEventObject():DynamicCast('wxTextCtrl') - local ac = self.ac[obj:GetId()] - if not ac then return end - - local keycode, needac = ac.lastkeycode, ac.needautocomplete - if needac then ac.needautocomplete = false end - if not needac or not keycode then return end - - -- if the last key was Delete or Backspace, don't autocomplete - if keycode == wx.WXK_DELETE or keycode == wx.WXK_BACK then return end - - -- find match for the current text and add it to the control - local value = obj:GetValue() - if not value or #value == 0 then return end - - local patt, match = "^"..q(value) - for _, v in ipairs( - obj:GetId() == self.findCtrl:GetId() and self.settings.flist or - obj:GetId() == self.replaceCtrl:GetId() and self.settings.rlist or - {} - ) do - if v:find(patt) then match = v; break end - end - if match then - obj:ChangeValue(match) - obj:SetSelection(#value, #match) - end - end - - local function findIncremental(event) - -- don't do any incremental search when search in selection - if self.inselection then return end - - if not self.infiles and self.backfocus and self.backfocus.position then - self:GetEditor():SetSelection(self.backfocus.position, self.backfocus.position) - end - -- don't search when used with "infiles", but still trigger autocomplete - if self.infiles or self:Find() then - self.ac[event:GetEventObject():DynamicCast('wxTextCtrl'):GetId()].needautocomplete = true - end - end - - local function findReplaceNext() - updateLists() - if findReplace.replace then - if findReplace.infiles then - findReplace:RunInFiles(true) - else - local replaceAll = (wx.wxGetKeyState(wx.WXK_ALT) - and not wx.wxGetKeyState(wx.WXK_SHIFT) and not wx.wxGetKeyState(wx.WXK_CONTROL)) - findReplace:Replace(replaceAll) - end - end - end - - local function findReplaceAll() - updateLists() - if findReplace.replace then - if findReplace.infiles then - findReplace:RunInFiles(true) - else - findReplace:Replace(true) - end - end - end - - local function onPanelPaint() - local dc = wx.wxBufferedPaintDC(ctrl) - local psize = ctrl:GetClientSize() - dc:SetBrush(bbrush) - dc:SetPen(bpen) - dc:DrawRectangle(0, 0, psize:GetWidth(), psize:GetHeight()) - dc:SetPen(wx.wxNullPen) - dc:SetBrush(wx.wxNullBrush) - dc:delete() - end - - ctrl:Connect(wx.wxEVT_PAINT, onPanelPaint) - ctrl:Connect(wx.wxEVT_ERASE_BACKGROUND, function() end) - - local taborder = {findCtrl, replaceCtrl, scope} - local function keyHandle(event) - local keycode = event:GetKeyCode() - self.ac[event:GetEventObject():DynamicCast('wxTextCtrl'):GetId()].lastkeycode = keycode - if keycode == wx.WXK_ESCAPE then - self:Hide(event:ShiftDown()) - elseif keycode == wx.WXK_TAB then - local id = event:GetId() - local order, pos = {} - for _, v in ipairs(taborder) do - if v:IsEnabled() and v:IsShown() then table.insert(order, v) end - if v:GetId() == id then pos = #order end - end - if not pos then return end - pos = pos + (event:ShiftDown() and -1 or 1) - if pos == 0 then pos = #order - elseif pos > #order then pos = 1 - end - order[pos]:SetFocus() - if order[pos] ~= scope then order[pos]:SetSelection(-1, -1) end - else - event:Skip() - end - end - - -- remember the current position in the editor when setting focus on find - local function refreshEditorInfo() - local ed = self:GetEditor() - if ed and ed ~= self.oveditor then - local spos, epos = ed:GetSelectionStart(), ed:GetSelectionEnd() - if not self.backfocus or self.backfocus.editor ~= ed then - self.backfocus = { editor = ed, spos = spos, epos = epos } - end - local bf = self.backfocus - bf.position = spos == epos and ed:GetCurrentPos() or spos - local inselection = ed:LineFromPosition(spos) ~= ed:LineFromPosition(epos) - - -- when the focus is changed, don't remove current "inselection" status as the - -- selection may change to highlight the match; not doing this makes it difficult - -- to switch between searching and replacing without losing the current match - if inselection and (not self.inselection or bf.spos ~= spos or bf.epos ~= epos) then - bf.spos = spos - bf.epos = epos - self.inselection = inselection - self:refreshToolbar() - end - end - end - findCtrl:Connect(wx.wxEVT_SET_FOCUS, - function(event) - event:Skip() - refreshEditorInfo() - end) - findCtrl:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, findNext) - findCtrl:Connect(wx.wxEVT_COMMAND_TEXT_UPDATED, findIncremental) - findCtrl:Connect(wx.wxEVT_KEY_DOWN, keyHandle) - replaceCtrl:Connect(wx.wxEVT_SET_FOCUS, function(event) - event:Skip() - refreshEditorInfo() - -- hide the replace hint; should be done with SetHint method, - -- but it's not yet available in wxlua 2.8.12 - if replaceCtrl:GetValue() == replaceHintText then replaceCtrl:ChangeValue('') end - end) - replaceCtrl:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, findReplaceNext) - replaceCtrl:Connect(wx.wxEVT_COMMAND_TEXT_UPDATED, function(event) - self.ac[event:GetEventObject():DynamicCast('wxTextCtrl'):GetId()].needautocomplete = true - end) - replaceCtrl:Connect(wx.wxEVT_KEY_DOWN, keyHandle) - - -- autocomplete for find/replace can be done from TEXT_UPDATED event, - -- but SetSelection doesn't work from TEXT_UPDATED event on Linux, - -- which makes it impossible to select the suggested part. - -- IDLE event is used instead to provide autocomplete suggestions. - findCtrl:Connect(wx.wxEVT_IDLE, autoComplete) - replaceCtrl:Connect(wx.wxEVT_IDLE, autoComplete) - - scope:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, findNext) - scope:Connect(wx.wxEVT_KEY_DOWN, keyHandle) - - local function notSearching(event) event:Enable(not self.oveditor) end - ctrl:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI, notSearching) - ctrl:Connect(ID_FINDREPLACENEXT, wx.wxEVT_UPDATE_UI, notSearching) - ctrl:Connect(ID_FINDREPLACEALL, wx.wxEVT_UPDATE_UI, notSearching) - - ctrl:Connect(ID_FINDNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, findNext) - ctrl:Connect(ID_FINDREPLACENEXT, wx.wxEVT_COMMAND_MENU_SELECTED, findReplaceNext) - ctrl:Connect(ID_FINDREPLACEALL, wx.wxEVT_COMMAND_MENU_SELECTED, findReplaceAll) - - ctrl:Connect(ID_FINDSETDIR, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local dir, mask = self:GetScope() - local filePicker = wx.wxDirDialog(ctrl, TR("Choose a search directory"), - dir or wx.wxGetCwd(), wx.wxFLP_USE_TEXTCTRL) - if filePicker:ShowModal(true) == wx.wxID_OK then - self:refreshToolbar(self:SetScope(FixDir(filePicker:GetPath()), mask)) - end - end) - - self.findCtrl = findCtrl - self.replaceCtrl = replaceCtrl - self.findSizer = findSizer -end - -function findReplace:refreshPanel(replace, infiles) - if not self.panel then self:createPanel() end - - self:GetEditor(true) -- remember the current editor - - local ctrl = self.panel - - -- check if a proper pane is already populated - if self.replace ~= replace or self.infiles ~= infiles then - self.replace = replace - self.infiles = infiles - - if replace then - self.findSizer:Show(1) - if self.replaceCtrl:GetValue() == '' then - self.replaceCtrl:ChangeValue(replaceHintText) - end - else - self.findSizer:Hide(1) - end - self.findSizer:Layout() - - self.scope:Show(infiles) - end - - local value = self.scope:GetValue() - local ed = ide:GetEditor() - if ed and (not value or #value == 0) then - local doc = ide:GetDocument(ed) - local ext = doc:GetFileExt() - local proj = ide:GetProject() - value = (proj and self:GetScopeMRU(proj..sep) or - self:SetScope(proj or wx.wxGetCwd(), '*.'..(#ext > 0 and ext or '*'))) - end - if ed then -- check if there is any selection - self.backfocus = nil - self.inselection = ed:LineFromPosition(ed:GetSelectionStart()) ~= - ed:LineFromPosition(ed:GetSelectionEnd()) - end - self:refreshToolbar(value) - - local mgr = ide:GetUIManager() - local pane = mgr:GetPane(searchpanel) - if not pane:IsShown() then - local size = ctrl:GetSize() - pane:Dock():Bottom():BestSize(size):MinSize(size):Layer(0):Row(1):Show() - mgr:Update() - - self:SetStatus(TR("Use %s to close."):format("`Escape`")) - end - - -- set value from the current selection (if any) - self.findCtrl:ChangeValue(self:GetSelection() or self.findCtrl:GetValue()) - - -- reset search when re-creating dialog to avoid modifying selected - -- fragment after successful search and updated replacement - self.foundString = false - self.findCtrl:SetFocus() - self.findCtrl:SetSelection(-1, -1) -- select the content -end - -function findReplace:Show(replace,infiles) - self:refreshPanel(replace,infiles) -end - -function findReplace:IsShown() - local pane = ide:GetUIManager():GetPane(searchpanel) - return pane:IsOk() and pane:IsShown() -end - -function findReplace:Hide(restorepos) - local ctrl = self.panel:FindFocus() - if not ctrl or ctrl:GetParent():GetId() ~= self.panel:GetId() then - -- if focus outside of the search panel, do nothing - elseif self.backfocus and ide:IsValidCtrl(self.backfocus.editor) then - local editor = self.backfocus.editor - -- restore original position for Shift-Esc or failed search - if restorepos or self.foundString == false then - editor:SetSelection(self.backfocus.spos, self.backfocus.epos) - end - editor:SetFocus() - elseif self:IsPreview(self.reseditor) then -- there is a preview, go there - self.reseditor:SetFocus() - end - - local mgr = ide:GetUIManager() - mgr:GetPane(searchpanel):Hide() - mgr:Update() -end - -local package = ide:AddPackage('core.findreplace', { - onProjectLoad = function() - if not findReplace.panel then return end -- not set yet - local _, mask = findReplace:GetScope() - local proj = ide:GetProject() - -- find the last used scope for the same project on the scope history - findReplace:refreshToolbar(findReplace:GetScopeMRU(proj..sep) - or findReplace:SetScope(proj, mask)) - end, - - onEditorPreSave = function(self, editor, filePath) - if not findReplace:IsPreview(editor) then return end - - local isModified = editor:GetModify() - if editor.replace and isModified then - findReplace:SetStatus("") - - local line = NOTFOUND - local oveditor = ide:CreateStyledTextCtrl(findReplace.panel, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(0,0), wx.wxBORDER_NONE) - local files, lines = 0, 0 - local report - while true do - -- for each marker that marks a file (MarkerNext) - line = editor:MarkerNext(line + 1, FILE_MARKER_VALUE) - if line == NOTFOUND then break end - - local fname = getRawLine(editor, line) -- get the file name - local filetext, err = FileRead(fname) - local mismatch = false - if filetext then - findReplace:SetStatus(GetFileName(fname)) - wx.wxSafeYield() - - oveditor:SetTextDyn(filetext) - while true do -- for each line following the file name - line = line + 1 - local text = getRawLine(editor, line) - local lnum, lmark, ltext = text:match("^%s*(%d+)([ :]) (.*)") - if lnum then - lnum = tonumber(lnum) - if lmark == ':' then -- if the change line, then apply the change - local pos = oveditor:PositionFromLine(lnum-1) - if pos == NOTFOUND then - mismatch = lnum - break - end - oveditor:SetTargetStart(pos) - oveditor:SetTargetEnd(pos+#getRawLine(oveditor, lnum-1)) - oveditor:ReplaceTarget(ltext) - lines = lines + 1 - -- if the context line, then check the context - elseif getRawLine(oveditor, lnum-1) ~= ltext then - mismatch = lnum - break - end - -- if not placeholder line " ...", then abort - elseif not text:find("^%s*%.+$") then - break - end - end - if lines > 0 and not mismatch then -- save the file - local ok - ok, err = FileWrite(fname, oveditor:GetTextDyn()) - if ok then files = files + 1 end - end - end - if err or mismatch then - report = (report or "") .. (("\n%s: %s") - :format(fname, mismatch and "mismatch on line "..mismatch or err)) - end - end - oveditor:Destroy() -- destroy the editor to release its memory - if report then editor:AppendTextDyn("\n"..report) end - editor:AppendTextDyn(("\n\nUpdated %d %s in %d %s.") - :format( - lines, makePlural("line", lines), - files, makePlural("file", files))) - editor:EnsureVisibleEnforcePolicy(editor:GetLineCount()-1) - editor:SetSavePoint() -- set unmodified status when done - findReplace:SetStatus(TR("Updated %d file.", files):format(files)) - return false - - -- don't offer to save file if called from SaveFile; - -- can still be used with explicit SaveFileAs - elseif not filePath and not isModified then - return false - end - end - }) - -function findReplace:SaveSettings() package:SetSettings(self.settings) end -MergeSettings(findReplace.settings, package:GetSettings()) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/gui.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/gui.lua deleted file mode 100644 index f4ea34e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/gui.lua +++ /dev/null @@ -1,567 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) --- Lomtik Software (J. Winwood & John Labenski) ---------------------------------------------------------- - -local ide = ide -local unpack = table.unpack or unpack - --- Pick some reasonable fixed width fonts to use for the editor -local function setFont(style, config) - return wx.wxFont(config.fontsize or 10, wx.wxFONTFAMILY_MODERN, style, - wx.wxFONTWEIGHT_NORMAL, false, config.fontname or "", - config.fontencoding or wx.wxFONTENCODING_DEFAULT) -end -ide.font.eNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.editor) -ide.font.eItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.editor) - -ide.font.oNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.outputshell) -ide.font.oItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.outputshell) - --- treeCtrl font requires slightly different handling -do local gui, config = wx.wxTreeCtrl():GetFont(), ide.config.filetree - if config.fontsize then gui:SetPointSize(config.fontsize) end - if config.fontname then gui:SetFaceName(config.fontname) end - ide.font.fNormal = gui -end - --- ---------------------------------------------------------------------------- --- Create the wxFrame --- ---------------------------------------------------------------------------- -local function createFrame() - local frame = wx.wxFrame(wx.NULL, wx.wxID_ANY, GetIDEString("editor"), - wx.wxDefaultPosition, wx.wxSize(1100, 700)) - frame:Center() - -- wrap into protected call as DragAcceptFiles fails on MacOS with - -- wxwidgets 2.8.12 even though it should work according to change notes - -- for 2.8.10: "Implemented wxWindow::DragAcceptFiles() on all platforms." - pcall(function() frame:DragAcceptFiles(true) end) - frame:Connect(wx.wxEVT_DROP_FILES,function(evt) - local files = evt:GetFiles() - if not files or #files == 0 then return end - for _, f in ipairs(files) do - LoadFile(f,nil,true) - end - end) - - -- update best size of the toolbar after resizing - frame:Connect(wx.wxEVT_SIZE, function(event) - local mgr = ide:GetUIManager() - local toolbar = mgr:GetPane("toolbar") - if toolbar and toolbar:IsOk() then - toolbar:BestSize(event:GetSize():GetWidth(), ide:GetToolBar():GetClientSize():GetHeight()) - mgr:Update() - end - end) - - local menuBar = wx.wxMenuBar() - local statusBar = frame:CreateStatusBar(5) - local section_width = statusBar:GetTextExtent("OVRW") - statusBar:SetStatusStyles({wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT}) - statusBar:SetStatusWidths({-1, section_width, section_width, section_width*5, section_width*4}) - statusBar:SetStatusText(GetIDEString("statuswelcome")) - statusBar:Connect(wx.wxEVT_LEFT_DOWN, function (event) - local rect = wx.wxRect() - statusBar:GetFieldRect(4, rect) - if rect:Contains(event:GetPosition()) then -- click on the interpreter - local menuitem = ide:FindMenuItem(ID.INTERPRETER) - if menuitem then - local menu = ide:CloneMenu(menuitem:GetSubMenu()) - if menu then statusBar:PopupMenu(menu) end - end - end - end) - - local mgr = wxaui.wxAuiManager() - mgr:SetManagedWindow(frame) - -- allow the panes to be larger than the defalt 1/3 of the main window size - mgr:SetDockSizeConstraint(0.8,0.8) - - frame.menuBar = menuBar - frame.statusBar = statusBar - frame.uimgr = mgr - - return frame -end - -local function SCinB(id) -- shortcut in brackets - local shortcut = KSC(id):gsub("\t","") - return shortcut and #shortcut > 0 and (" ("..shortcut..")") or "" -end - -local function menuDropDownPosition(event) - local tb = event:GetEventObject():DynamicCast('wxAuiToolBar') - local rect = tb:GetToolRect(event:GetId()) - return ide.frame:ScreenToClient(tb:ClientToScreen(rect:GetBottomLeft())) -end - -local function tbIconSize() - -- use large icons by default on OSX and on large screens - local iconsize = (tonumber(ide.config.toolbar and ide.config.toolbar.iconsize) - or ((ide.osname == 'Macintosh' or wx.wxGetClientDisplayRect():GetWidth() >= 1500) and 24 or 16)) - if iconsize ~= 24 then iconsize = 16 end - return iconsize -end - -local function createToolBar(frame) - local toolBar = wxaui.wxAuiToolBar(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, - wxaui.wxAUI_TB_PLAIN_BACKGROUND) - - -- there are two sets of icons: use 24 on OSX and 16 on others. - local iconsize = tbIconSize() - local toolBmpSize = wx.wxSize(iconsize, iconsize) - local icons, prev = ide.config.toolbar.icons - for _, id in ipairs(icons) do - if icons[id] ~= false then -- skip explicitly disabled icons - if id == ID_SEPARATOR then - -- make sure that there are no two separators next to each other; - -- this may happen when some of the icons are disabled. - if prev ~= ID_SEPARATOR then toolBar:AddSeparator() end - else - local iconmap = ide.config.toolbar.iconmap[id] - if iconmap then - local icon, description = unpack(iconmap) - local isbitmap = type(icon) == "userdata" and icon:GetClassInfo():GetClassName() == "wxBitmap" - local bitmap = isbitmap and icon or ide:GetBitmap(icon, "TOOLBAR", toolBmpSize) - toolBar:AddTool(id, "", bitmap, (TR)(description)..SCinB(id)) - end - end - prev = id - end - end - - toolBar:SetToolDropDown(ID_OPEN, true) - toolBar:Connect(ID_OPEN, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event) - if event:IsDropDownClicked() then - local menu = wx.wxMenu() - FileRecentListUpdate(menu) - toolBar:PopupMenu(menu, menuDropDownPosition(event)) - else - event:Skip() - end - end) - - toolBar:SetToolDropDown(ID_PROJECTDIRCHOOSE, true) - toolBar:Connect(ID_PROJECTDIRCHOOSE, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event) - if event:IsDropDownClicked() then - local menu = wx.wxMenu() - FileTreeProjectListUpdate(menu, 0) - toolBar:PopupMenu(menu, menuDropDownPosition(event)) - else - event:Skip() - end - end) - - toolBar:GetArtProvider():SetElementSize(wxaui.wxAUI_TBART_GRIPPER_SIZE, 0) - toolBar:Realize() - - frame.toolBar = toolBar - return toolBar -end - -local function createNotebook(frame) - -- notebook for editors - local notebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, - wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - + wxaui.wxAUI_NB_WINDOWLIST_BUTTON + wx.wxNO_BORDER) - - -- wxEVT_SET_FOCUS could be used, but it only works on Windows with wx2.9.5+ - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, - function (event) - local ed = GetEditor(notebook:GetSelection()) - local doc = ed and ed:GetId() and ide.openDocuments[ed:GetId()] - - -- skip activation when any of the following is true: - -- (1) there is no document yet, the editor tab was just added, - -- so no changes needed as there will be a proper later call; - -- (2) the page change event was triggered after a tab is closed; - -- (3) on OSX from AddPage event when changing from the last tab - -- (this is to work around a duplicate event generated in this case - -- that first activates the added tab and then some other tab (2.9.5)). - - local double = (ide.osname == 'Macintosh' - and event:GetOldSelection() == notebook:GetPageCount() - and debug:traceback():find("'AddPage'")) - - if doc and event:GetOldSelection() ~= -1 and not double then - SetEditorSelection(notebook:GetSelection()) - end - end) - - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, - function (event) - ClosePage(event:GetSelection()) - event:Veto() -- don't propagate the event as the page is already closed - end) - - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, - function (event) - -- as this event can be on different tab controls, - -- need to find the control to add the page to - local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") - -- check if the active page is in the current control - local active = tabctrl:GetActivePage() - if (active >= 0 and tabctrl:GetPage(active).window - ~= notebook:GetPage(notebook:GetSelection())) then - -- if not, need to activate the control that was clicked on; - -- find the last window and switch to it (assuming there is always one) - assert(tabctrl:GetPageCount() >= 1, "Expected at least one page in a notebook tab control.") - local lastwin = tabctrl:GetPage(tabctrl:GetPageCount()-1).window - notebook:SetSelection(notebook:GetPageIndex(lastwin)) - end - NewFile() - end) - - -- tabs can be dragged around which may change their indexes; - -- when this happens stored indexes need to be updated to reflect the change. - -- there is DRAG_DONE event that I'd prefer to use, but it - -- doesn't fire for some reason using wxwidgets 2.9.5 (tested on Windows). - if ide.wxver >= "2.9.5" then - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, - function (event) - for page = 0, notebook:GetPageCount()-1 do - local editor = GetEditor(page) - if editor then ide.openDocuments[editor:GetId()].index = page end - end - -- first set the selection on the dragged tab to reset its state - notebook:SetSelection(event:GetSelection()) - -- select the content of the tab after drag is done - SetEditorSelection(event:GetSelection()) - event:Skip() - end) - end - - local selection - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, - function (event) - -- event:GetSelection() returns the index *inside the current tab*; - -- for split notebooks, this may not be the same as the index - -- in the notebook we are interested in here - local idx = event:GetSelection() - local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") - - -- save tab index the event is for - selection = notebook:GetPageIndex(tabctrl:GetPage(idx).window) - - local menu = wx.wxMenu { - { ID_CLOSE, TR("&Close Page") }, - { ID_CLOSEALL, TR("Close A&ll Pages") }, - { ID_CLOSEOTHER, TR("Close &Other Pages") }, - { }, - { ID_SAVE, TR("&Save") }, - { ID_SAVEAS, TR("Save &As...") }, - { }, - { ID_COPYFULLPATH, TR("Copy Full Path") }, - { ID_SHOWLOCATION, TR("Show Location") }, - } - - PackageEventHandle("onMenuEditorTab", menu, notebook, event, selection) - - notebook:PopupMenu(menu) - end) - - local function IfAtLeastOneTab(event) - event:Enable(notebook:GetPageCount() > 0) - if ide.osname == 'Macintosh' and (event:GetId() == ID_CLOSEALL - or event:GetId() == ID_CLOSE and notebook:GetPageCount() <= 1) - then event:Enable(false) end - end - - notebook:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED, function () - ide:GetDocument(GetEditor(selection)):Save() - end) - notebook:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI, function(event) - local doc = ide:GetDocument(GetEditor(selection)) - event:Enable(doc:IsModified() or doc:IsNew()) - end) - notebook:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED, function() - SaveFileAs(GetEditor(selection)) - end) - notebook:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) - notebook:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED, function() - ClosePage(selection) - end) - notebook:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) - notebook:Connect(ID_CLOSEALL, wx.wxEVT_COMMAND_MENU_SELECTED, function() - CloseAllPagesExcept(nil) - end) - notebook:Connect(ID_CLOSEALL, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) - notebook:Connect(ID_CLOSEOTHER, wx.wxEVT_COMMAND_MENU_SELECTED, function () - CloseAllPagesExcept(selection) - end) - notebook:Connect(ID_CLOSEOTHER, wx.wxEVT_UPDATE_UI, function (event) - event:Enable(notebook:GetPageCount() > 1) - end) - notebook:Connect(ID_SHOWLOCATION, wx.wxEVT_COMMAND_MENU_SELECTED, function() - ShowLocation(ide:GetDocument(GetEditor(selection)):GetFilePath()) - end) - notebook:Connect(ID_SHOWLOCATION, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) - - notebook:Connect(ID_COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED, function() - ide:CopyToClipboard(ide:GetDocument(GetEditor(selection)):GetFilePath()) - end) - - frame.notebook = notebook - return notebook -end - -local function addDND(notebook) - -- this handler allows dragging tabs into this notebook - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, - function (event) - local notebookfrom = event:GetDragSource() - if notebookfrom ~= ide.frame.notebook then - -- disable cross-notebook movement of specific tabs - local win = notebookfrom:GetPage(event:GetSelection()) - if not win then return end - local winid = win:GetId() - if winid == ide:GetOutput():GetId() - or winid == ide:GetConsole():GetId() - or winid == ide:GetProjectTree():GetId() - or ide.findReplace:IsPreview(win) -- search results preview - then return end - - local mgr = ide.frame.uimgr - local pane = mgr:GetPane(notebookfrom) - if not pane:IsOk() then return end -- not a managed window - if pane:IsFloating() then - notebookfrom:GetParent():Hide() - else - pane:Hide() - mgr:Update() - end - mgr:DetachPane(notebookfrom) - - -- this is a workaround for wxwidgets bug (2.9.5+) that combines - -- content from two windows when tab is dragged over an active tab. - local mouse = wx.wxGetMouseState() - local mouseatpoint = wx.wxPoint(mouse:GetX(), mouse:GetY()) - local ok, tabs = pcall(function() return wx.wxFindWindowAtPoint(mouseatpoint):DynamicCast("wxAuiTabCtrl") end) - if ok then tabs:SetNoneActive() end - - event:Allow() - end - end) - - -- these handlers allow dragging tabs out of this notebook. - -- I couldn't find a good way to stop dragging event as it's not known - -- where the event is going to end when it's started, so we manipulate - -- the flag that allows splits and disable it when needed. - -- It is then enabled in BEGIN_DRAG event. - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, - function (event) - event:Skip() - - -- allow dragging if it was disabled earlier - local flags = notebook:GetWindowStyleFlag() - if bit.band(flags, wxaui.wxAUI_NB_TAB_SPLIT) == 0 then - notebook:SetWindowStyleFlag(flags + wxaui.wxAUI_NB_TAB_SPLIT) - end - end) - - -- there is currently no support in wxAuiNotebook for dragging tabs out. - -- This is implemented as removing a tab that was dragged out and - -- recreating it with the right control. This is complicated by the fact - -- that tabs can be split, so if the destination is withing the area where - -- splits happen, the tab is not removed. - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, - function (event) - event:Skip() - - local mgr = ide.frame.uimgr - local win = mgr:GetPane(notebook).window - local x = win:GetScreenPosition():GetX() - local y = win:GetScreenPosition():GetY() - local w, h = win:GetSize():GetWidth(), win:GetSize():GetHeight() - - local mouse = wx.wxGetMouseState() - local mx, my = mouse:GetX(), mouse:GetY() - - if mx >= x and mx <= x + w and my >= y and my <= y + h then return end - - -- disallow split as the target is outside the notebook - local flags = notebook:GetWindowStyleFlag() - if bit.band(flags, wxaui.wxAUI_NB_TAB_SPLIT) ~= 0 then - notebook:SetWindowStyleFlag(flags - wxaui.wxAUI_NB_TAB_SPLIT) - end - - -- don't allow dragging out single tabs from tab ctrl - -- as wxwidgets doesn't like removing pages from split notebooks. - local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") - if tabctrl:GetPageCount() == 1 then return end - - local idx = event:GetSelection() -- index within the current tab ctrl - local selection = notebook:GetPageIndex(tabctrl:GetPage(idx).window) - local label = notebook:GetPageText(selection) - local pane = ide:RestorePanelByLabel(label) - if not pane then return end - - pane:FloatingPosition(mx-10, my-10) - pane:Show() - notebook:RemovePage(selection) - mgr:Update() - end) -end - -local function createBottomNotebook(frame) - -- bottomnotebook (errorlog,shellbox) - local bottomnotebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, - wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER) - - addDND(bottomnotebook) - - bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, - function (event) - if not ide.findReplace then return end - local nb = event:GetEventObject():DynamicCast("wxAuiNotebook") - local preview = ide.findReplace:IsPreview(nb:GetPage(nb:GetSelection())) - local flags = nb:GetWindowStyleFlag() - if preview and bit.band(flags, wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) == 0 then - nb:SetWindowStyleFlag(flags + wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) - elseif not preview and bit.band(flags, wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) ~= 0 then - nb:SetWindowStyleFlag(flags - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) - end - end) - - -- disallow tabs closing - bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, - function (event) - local nb = event:GetEventObject():DynamicCast("wxAuiNotebook") - if ide.findReplace - and ide.findReplace:IsPreview(nb:GetPage(nb:GetSelection())) then - event:Skip() - else - event:Veto() - end - end) - - local errorlog = ide:CreateStyledTextCtrl(bottomnotebook, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE) - - errorlog:Connect(wx.wxEVT_CONTEXT_MENU, - function (event) - local menu = wx.wxMenu { - { ID_UNDO, TR("&Undo") }, - { ID_REDO, TR("&Redo") }, - { }, - { ID_CUT, TR("Cu&t") }, - { ID_COPY, TR("&Copy") }, - { ID_PASTE, TR("&Paste") }, - { ID_SELECTALL, TR("Select &All") }, - { }, - { ID_CLEAROUTPUT, TR("C&lear Output Window") }, - } - PackageEventHandle("onMenuOutput", menu, errorlog, event) - errorlog:PopupMenu(menu) - end) - - errorlog:Connect(ID_CLEAROUTPUT, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) ClearOutput(true) end) - - local shellbox = ide:CreateStyledTextCtrl(bottomnotebook, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE) - - local menupos - shellbox:Connect(wx.wxEVT_CONTEXT_MENU, - function (event) - local menu = wx.wxMenu { - { ID_UNDO, TR("&Undo") }, - { ID_REDO, TR("&Redo") }, - { }, - { ID_CUT, TR("Cu&t") }, - { ID_COPY, TR("&Copy") }, - { ID_PASTE, TR("&Paste") }, - { ID_SELECTALL, TR("Select &All") }, - { }, - { ID_SELECTCONSOLECOMMAND, TR("&Select Command") }, - { ID_CLEARCONSOLE, TR("C&lear Console Window") }, - } - menupos = event:GetPosition() - PackageEventHandle("onMenuConsole", menu, shellbox, event) - shellbox:PopupMenu(menu) - end) - - shellbox:Connect(ID_SELECTCONSOLECOMMAND, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) ConsoleSelectCommand(menupos) end) - shellbox:Connect(ID_CLEARCONSOLE, wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) ide:GetConsole():Erase() end) - - bottomnotebook:AddPage(errorlog, TR("Output"), true) - bottomnotebook:AddPage(shellbox, TR("Local console"), false) - - bottomnotebook.errorlog = errorlog - bottomnotebook.shellbox = shellbox - - frame.bottomnotebook = bottomnotebook - return bottomnotebook -end - -local function createProjNotebook(frame) - local projnotebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, - wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER) - - addDND(projnotebook) - - -- disallow tabs closing - projnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, - function (event) event:Veto() end) - - frame.projnotebook = projnotebook - return projnotebook -end - --- ---------------------------------------------------------------------------- --- Add the child windows to the frame - -local frame = createFrame() -ide.frame = frame -createToolBar(frame) -createNotebook(frame) -createProjNotebook(frame) -createBottomNotebook(frame) - -do - local frame = ide.frame - local mgr = frame.uimgr - - --[[mgr:AddPane(frame.toolBar, wxaui.wxAuiPaneInfo(): - Name("toolbar"):Caption("Toolbar"): - ToolbarPane():Top():CloseButton(false):PaneBorder(false): - LeftDockable(false):RightDockable(false))]]-- - mgr:AddPane(frame.notebook, wxaui.wxAuiPaneInfo(): - Name("notebook"): - CenterPane():PaneBorder(false)) - mgr:AddPane(frame.projnotebook, wxaui.wxAuiPaneInfo(): - Name("projpanel"):CaptionVisible(false): - MinSize(200,200):FloatingSize(200,400): - Left():Layer(1):Position(1):PaneBorder(false): - CloseButton(true):MaximizeButton(false):PinButton(true)) - mgr:AddPane(frame.bottomnotebook, wxaui.wxAuiPaneInfo(): - Name("bottomnotebook"):CaptionVisible(false): - MinSize(100,100):BestSize(200,200):FloatingSize(400,200): - Bottom():Layer(1):Position(1):PaneBorder(false): - CloseButton(true):MaximizeButton(false):PinButton(true)) - --mgr:GetPane("toolbar"):Show(false) - mgr:GetPane("projpanel"):Show(false) - mgr:GetPane("bottomnotebook"):Show(false) - - if type(ide.config.bordersize) == 'number' then - for _, uimgr in pairs {mgr, frame.notebook:GetAuiManager(), - frame.bottomnotebook:GetAuiManager(), frame.projnotebook:GetAuiManager()} do - uimgr:GetArtProvider():SetMetric(wxaui.wxAUI_DOCKART_SASH_SIZE, - ide.config.bordersize) - end - end - - for _, nb in pairs {frame.bottomnotebook, frame.projnotebook} do - nb:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, - function() PaneFloatToggle(nb) end) - end - - mgr.defaultPerspective = mgr:SavePerspective() -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/ids.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/ids.lua deleted file mode 100644 index d53ae83..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/ids.lua +++ /dev/null @@ -1,190 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - --- Generate a unique new wxWindowID -local ID_IDCOUNTER = wx.wxID_HIGHEST + 1 -function NewID() - ID_IDCOUNTER = ID_IDCOUNTER + 1 - return ID_IDCOUNTER -end - --- some Ubuntu versions (Ubuntu 13.10) ignore labels on stock menu IDs, --- so don't use stock IDs on Linux -local linux = ide.osname == 'Unix' - -ID_SEPARATOR = NewID() --- File menu -ID_NEW = linux and NewID() or wx.wxID_NEW -ID_OPEN = linux and NewID() or wx.wxID_OPEN -ID_CLOSE = NewID() -ID_CLOSEALL = NewID() -ID_CLOSEOTHER = NewID() -ID_NEWFILE = NewID() -ID_NEWDIRECTORY = NewID() -ID_RENAMEFILE = NewID() -ID_DELETEFILE = NewID() -ID_SAVE = linux and NewID() or wx.wxID_SAVE -ID_SAVEAS = linux and NewID() or wx.wxID_SAVEAS -ID_SAVEALL = NewID() -ID_RECENTFILES = NewID() -ID_RECENTFILESCLEAR = NewID() -ID_RECENTFILESPREV = NewID() -ID_RECENTFILESNEXT = NewID() -ID_RECENTPROJECTS = NewID() -ID_RECENTPROJECTSCLEAR = NewID() -ID_RECENTPROJECTSPREV = NewID() -ID_PRINT = NewID() -ID_PAGESETUP = NewID() -ID_EXIT = linux and NewID() or wx.wxID_EXIT --- Edit menu -ID_CUT = linux and NewID() or wx.wxID_CUT -ID_COPY = linux and NewID() or wx.wxID_COPY -ID_PASTE = linux and NewID() or wx.wxID_PASTE -ID_SELECTALL = linux and NewID() or wx.wxID_SELECTALL -ID_UNDO = linux and NewID() or wx.wxID_UNDO -ID_REDO = linux and NewID() or wx.wxID_REDO -ID_SHOWTOOLTIP = NewID() -ID_AUTOCOMPLETE = NewID() -ID_AUTOCOMPLETEENABLE = NewID() -ID_COMMENT = NewID() -ID_FOLD = NewID() -ID_CLEARDYNAMICWORDS = NewID() -ID_SOURCE = NewID() -ID_REINDENT = NewID() -ID_BOOKMARK = NewID() -ID_BOOKMARKTOGGLE = NewID() -ID_BOOKMARKNEXT = NewID() -ID_BOOKMARKPREV = NewID() -ID_NAVIGATE = NewID() -ID_NAVIGATETOFILE = NewID() -ID_NAVIGATETOLINE = NewID() -ID_NAVIGATETOSYMBOL = NewID() -ID_NAVIGATETOMETHOD = NewID() --- don't use wx.wxID_PREFERENCES to avoid merging with OSX app menu, because --- Apple guidelines describe Preferences as a "normal" item without submenus. -ID_PREFERENCES = NewID() -ID_PREFERENCESSYSTEM = NewID() -ID_PREFERENCESUSER = NewID() --- Search menu -ID_FIND = linux and NewID() or wx.wxID_FIND -ID_FINDNEXT = NewID() -ID_FINDPREV = NewID() -ID_FINDSELECTNEXT = NewID() -ID_FINDSELECTPREV = NewID() -ID_REPLACE = NewID() -ID_FINDINFILES = NewID() -ID_REPLACEINFILES = NewID() -ID_SORT = NewID() --- View menu -ID_VIEWFILETREE = NewID() -ID_VIEWOUTPUT = NewID() -ID_VIEWCALLSTACK = NewID() -ID_VIEWWATCHWINDOW = NewID() -ID_VIEWOUTLINE = NewID() -ID_VIEWMARKERS = NewID() -ID_VIEWTOOLBAR = NewID() -ID_VIEWSTATUSBAR = NewID() -ID_VIEWDEFAULTLAYOUT = NewID() -ID_VIEWFULLSCREEN = NewID() -ID_VIEWMINIMIZE = NewID() -ID_ZOOM = NewID() -ID_ZOOMRESET = NewID() -ID_ZOOMIN = NewID() -ID_ZOOMOUT = NewID() --- Project menu -ID_BREAKPOINT = NewID() -ID_BREAKPOINTTOGGLE = NewID() -ID_BREAKPOINTNEXT = NewID() -ID_BREAKPOINTPREV = NewID() -ID_TOGGLEBREAKPOINT = ID_BREAKPOINTTOGGLE -- for compatibility; to remove after v1.30 -ID_COMPILE = NewID() -ID_ANALYZE = NewID() -ID_RUN = NewID() -ID_RUNNOW = NewID() -ID_ATTACHDEBUG = NewID() -ID_STARTDEBUG = NewID() -ID_STOPDEBUG = NewID() -ID_DETACHDEBUG = NewID() -ID_STEP = NewID() -ID_STEPOVER = NewID() -ID_STEPOUT = NewID() -ID_RUNTO = NewID() -ID_BREAK = NewID() -ID_TRACE = NewID() -ID_CLEAROUTPUT = NewID() -ID_CLEARCONSOLE = NewID() -ID_COMMANDLINEPARAMETERS = NewID() -ID_INTERPRETER = NewID() -ID_PROJECTDIR = NewID() -ID_PROJECTDIRFROMFILE = NewID() -ID_PROJECTDIRFROMDIR = NewID() -ID_PROJECTDIRCHOOSE = NewID() --- Help menu -ID_ABOUT = linux and NewID() or wx.wxID_ABOUT -ID_HELPPROJECT = NewID() -ID_HELPDOCUMENTATION = NewID() -ID_HELPGETTINGSTARTED = NewID() -ID_HELPTUTORIALS = NewID() -ID_HELPFAQ = NewID() -ID_HELPCOMMUNITY = NewID() --- Watch window menu items -ID_ADDWATCH = NewID() -ID_EDITWATCH = NewID() -ID_DELETEWATCH = NewID() -ID_COPYWATCHVALUE = NewID() --- Editor popup menu items -ID_GOTODEFINITION = NewID() -ID_RENAMEALLINSTANCES = NewID() -ID_REPLACEALLSELECTIONS = NewID() -ID_QUICKADDWATCH = NewID() -ID_QUICKEVAL = NewID() -ID_ADDTOSCRATCHPAD = NewID() --- filetree menu -ID_HIDEEXTENSION = NewID() -ID_SETSTARTFILE = NewID() -ID_UNSETSTARTFILE = NewID() -ID_SHOWEXTENSION = NewID() -ID_SHOWEXTENSIONALL = NewID() -ID_MAPDIRECTORY = NewID() -ID_UNMAPDIRECTORY = NewID() -ID_OPENEXTENSION = NewID() -ID_COPYFULLPATH = NewID() -ID_SHOWLOCATION = NewID() -ID_REFRESH = NewID() -ID_SYMBOLDIRREFRESH = NewID() -ID_SYMBOLDIRINDEX = NewID() -ID_SYMBOLDIRDISABLE = NewID() -ID_SYMBOLDIRENABLE = NewID() --- outline menu -ID_OUTLINESORT = NewID() --- console menu -ID_SELECTCONSOLECOMMAND = NewID() --- search toolbar -ID_FINDALL = NewID() -ID_FINDREPLACENEXT = NewID() -ID_FINDREPLACEALL = NewID() -ID_FINDSETDIR = NewID() -ID_FINDSETTOPROJDIR = NewID() -ID_FINDOPTSCOPE = NewID() -ID_FINDOPTSTATUS = NewID() -ID_FINDOPTDIRECTION = NewID() -ID_FINDOPTWRAPWROUND = NewID() -ID_FINDOPTSELECTION = NewID() -ID_FINDOPTWORD = NewID() -ID_FINDOPTCASE = NewID() -ID_FINDOPTREGEX = NewID() -ID_FINDOPTCONTEXT = NewID() -ID_FINDOPTSUBDIR = NewID() -ID_FINDOPTMULTIRESULTS = NewID() -ID_RECENTSCOPECLEAR = NewID() - -local ids = {} -function IDgen (name) - ids[name] = ids[name] or NewID() - return ids[name] -end -function IDget (name) return ids[name] end - -ID = setmetatable({}, ide.proto.ID) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/inspect.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/inspect.lua deleted file mode 100644 index a9eef01..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/inspect.lua +++ /dev/null @@ -1,243 +0,0 @@ --- Copyright 2012-15 Paul Kulchenko, ZeroBrane LLC --- Integration with LuaInspect ---------------------------------------------------------- - -local M, LA, LI, T = {} - -local function init() - if LA then return end - - -- metalua is using 'checks', which noticeably slows the execution - -- stab it with out own - package.loaded.checks = {} - checks = function() end - - LA = require "luainspect.ast" - LI = require "luainspect.init" - T = require "luainspect.types" -end - -function M.pos2line(pos) - return pos and 1 + select(2, M.src:sub(1,pos):gsub(".-\n[^\n]*", "")) -end - -function M.warnings_from_string(src, file) - init() - - local ast, err, linenum, colnum = LA.ast_from_string(src, file) - if not ast and err then return nil, err, linenum, colnum end - - LI.uninspect(ast) - if ide.config.staticanalyzer.infervalue then - local tokenlist = LA.ast_to_tokenlist(ast, src) - LI.clear_cache() - LI.inspect(ast, tokenlist, src) - LI.mark_related_keywords(ast, tokenlist, src) - else - -- stub out LI functions that depend on tokenlist, - -- which is not built in the "fast" mode - local ec, iv = LI.eval_comments, LI.infer_values - LI.eval_comments, LI.infer_values = function() end, function() end - - LI.inspect(ast, nil, src) - LA.ensure_parents_marked(ast) - - LI.eval_comments, LI.infer_values = ec, iv - end - - local globinit = {arg = true} -- skip `arg` global variable - local spec = GetSpec(wx.wxFileName(file):GetExt()) - for k in pairs(spec and GetApi(spec.apitype or "none").ac.childs or {}) do - globinit[k] = true - end - - M.src, M.file = src, file - return M.show_warnings(ast, globinit) -end - -local function cleanError(err) - return err and err:gsub(".-:%d+: file%s+",""):gsub(", line (%d+), char %d+", ":%1") -end - -function AnalyzeFile(file) - local src, err = FileRead(file) - if not src and err then return nil, TR("Can't open file '%s': %s"):format(file, err) end - - local warn, err, line, pos = M.warnings_from_string(src, file) - return warn, cleanError(err), line, pos -end - -function AnalyzeString(src, file) - local warn, err, line, pos = M.warnings_from_string(src, file or "") - return warn, cleanError(err), line, pos -end - -function M.show_warnings(top_ast, globinit) - local warnings = {} - local function warn(msg, linenum, path) - warnings[#warnings+1] = (path or M.file or "?") .. ":" .. (linenum or M.pos2line(M.ast.pos) or 0) .. ": " .. msg - end - local function known(o) return not T.istype[o] end - local function index(f) -- build abc.def.xyz name recursively - if not f or f.tag ~= 'Index' or not f[1] or not f[2] then return end - local main = f[1].tag == 'Id' and f[1][1] or index(f[1]) - return main and type(f[2][1]) == "string" and (main .. '.' .. f[2][1]) or nil - end - local globseen, isseen, fieldseen = globinit or {}, {}, {} - LA.walk(top_ast, function(ast) - M.ast = ast - local path, line = tostring(ast.lineinfo):gsub(' func.tag == 'Set' - -- `Set{{`Id{"foo"}},{`Function{{`Id{"bar"}},{}}}} - -- "local function foo(bar)" => func.tag == 'Localrec' - -- "local _, foo = 1, function(bar)" => func.tag == 'Local' - -- "print(function(bar) end)" => func.tag == nil - -- "a = a or function(bar) end" => func.tag == nil - -- "return(function(bar) end)" => func.tag == 'Return' - -- "function tbl:foo(bar)" => func.tag == 'Set' - -- `Set{{`Index{`Id{"tbl"},`String{"foo"}}},{`Function{{`Id{"self"},`Id{"bar"}},{}}}} - -- "function tbl.abc:foo(bar)" => func.tag == 'Set' - -- `Set{{`Index{`Index{`Id{"tbl"},`String{"abc"}},`String{"foo"}}},{`Function{{`Id{"self"},`Id{"bar"}},{}}}}, - warn("unused parameter '" .. name .. "'" .. - (func and (assignment or expression) - and (fname and func.tag - and (" in function '" .. fname .. "'") - or " in anonymous function") - or ""), - line, path) - end - else - if parent and parent.tag == 'Localrec' then -- local function foo... - warn("unused local function '" .. name .. "'", line, path) - else - warn("unused local variable '" .. name .. "'; ".. - "consider removing or replacing with '_'", line, path) - end - end - end - -- added check for "fast" mode as ast.seevalue relies on value evaluation, - -- which is very slow even on simple and short scripts - if ide.config.staticanalyzer.infervalue and ast.isfield - and not(known(ast.seevalue.value) and ast.seevalue.value ~= nil) then - if not fieldseen[name] then - fieldseen[name] = true - local var = index(ast.parent) - local parent = ast.parent and var - and (" in '"..var:gsub("%."..name.."$","").."'") - or "" - - local tblref = ast.parent and ast.parent[1] - local localparam = (tblref and tblref.localdefinition - and tblref.localdefinition.isparam) - if not localparam then - warn("first use of unknown field '" .. name .."'"..parent, - ast.lineinfo and tostring(ast.lineinfo.first):match('|L(%d+)'), path) - end - end - elseif ast.tag == 'Id' and not ast.localdefinition and not ast.definedglobal then - if not globseen[name] then - globseen[name] = true - local parent = ast.parent - -- if being called and not one of the parameters - if parent and parent.tag == 'Call' and parent[1] == ast then - warn("first use of unknown global function '" .. name .. "'", line, path) - else - warn("first use of unknown global variable '" .. name .. "'", line, path) - end - end - elseif ast.tag == 'Id' and not ast.localdefinition and ast.definedglobal then - local parent = ast.parent and ast.parent.parent - if parent and parent.tag == 'Set' and not globseen[name] -- report assignments to global - -- only report if it is on the left side of the assignment - -- this is a bit tricky as it can be assigned as part of a, b = c, d - -- `Set{ {lhs+} {expr+} } -- lhs1, lhs2... = e1, e2... - and parent[1] == ast.parent - and parent[2][1].tag ~= "Function" then -- but ignore global functions - warn("first assignment to global variable '" .. name .. "'", line, path) - globseen[name] = true - end - elseif (ast.tag == 'Set' or ast.tag == 'Local') and #(ast[2]) > #(ast[1]) then - warn(("value discarded in multiple assignment: %d values assigned to %d variable%s") - :format(#(ast[2]), #(ast[1]), #(ast[1]) > 1 and 's' or ''), line, path) - end - local vast = ast.seevalue or ast - local note = vast.parent - and (vast.parent.tag == 'Call' or vast.parent.tag == 'Invoke') - and vast.parent.note - if note and not isseen[vast.parent] and type(name) == "string" then - isseen[vast.parent] = true - warn("function '" .. name .. "': " .. note, line, path) - end - end) - return warnings -end - -local frame = ide.frame - --- insert after "Compile" item -local _, menu, compilepos = ide:FindMenuItem(ID_COMPILE) -if compilepos then - menu:Insert(compilepos+1, ID_ANALYZE, TR("Analyze")..KSC(ID_ANALYZE), TR("Analyze the source code")) -end - -local function analyzeProgram(editor) - -- save all files (if requested) for "infervalue" analysis to keep the changes on disk - if ide.config.editor.saveallonrun and ide.config.staticanalyzer.infervalue then SaveAll(true) end - if ide:GetLaunchedProcess() == nil and not ide:GetDebugger():IsConnected() then ClearOutput() end - DisplayOutput("Analyzing the source code") - frame:Update() - - local editorText = editor:GetTextDyn() - local doc = ide:GetDocument(editor) - local filePath = doc:GetFilePath() or doc:GetFileName() - local warn, err = M.warnings_from_string(editorText, filePath) - if err then -- report compilation error - DisplayOutputLn((": not completed.\n%s"):format(cleanError(err))) - return false - end - - DisplayOutputLn((": %s warning%s.") - :format(#warn > 0 and #warn or 'no', #warn == 1 and '' or 's')) - DisplayOutputNoMarker(table.concat(warn, "\n") .. (#warn > 0 and "\n" or "")) - - return true -- analyzed ok -end - -frame:Connect(ID_ANALYZE, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - ActivateOutput() - local editor = GetEditor() - if not analyzeProgram(editor) then - CompileProgram(editor, { reportstats = false, keepoutput = true }) - end - end) -frame:Connect(ID_ANALYZE, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(GetEditor() ~= nil) end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/iofilters.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/iofilters.lua deleted file mode 100644 index 76e6135..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/iofilters.lua +++ /dev/null @@ -1,71 +0,0 @@ --- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide - -ide.iofilters["GermanUtf8Ascii"] = { - - -- this function converts some utf8 character output. It's a hack. - -- Since luxinia is not utf8 prepared, this is still necessary. - -- if you wish to turn this off, edit user.lua and set this filefunction to nil - output = function (fpath, content) - local utf8escape = ("string").char(195) - -- only simple cases are handled (umlauts) - local chr = ("string").char - local charconv = { - [chr(164)] = chr(228), -- ä - [chr(182)] = chr(246), -- ö - [chr(188)] = chr(252), -- ü - [chr(132)] = chr(196), -- Ä - [chr(150)] = chr(214), -- Ö - [chr(156)] = chr(220), -- Ü - [chr(159)] = chr(223), -- ß - } - return content : gsub (utf8escape.."(.)",charconv) - end, - - -- this function is another hack to read an ANSI encoded - -- file and converts the umlauts to utf8 chars - input = function (fpath, content) - local utf8escape = ("string").char(195) - local chr = ("string").char - local charconv = { - [chr(228)] = utf8escape..chr(164), -- ä - [chr(246)] = utf8escape..chr(182), -- ö - [chr(252)] = utf8escape..chr(188), -- ü - [chr(196)] = utf8escape..chr(132), -- Ä - [chr(214)] = utf8escape..chr(150), -- Ö - [chr(220)] = utf8escape..chr(156), -- Ü - [chr(223)] = utf8escape..chr(159), -- ß - } - local lst = "[" - for k in pairs(charconv) do lst = lst .. k end - lst = lst.."]" - - return content:gsub(lst,charconv) - end, - -} - -ide.iofilters["0d0d0aFix"] = { - -- this function converts 0d0d0a line ending to 0d0a - input = function(fpath, content) - return content:gsub("\013\013\010","\013\010") - end, -} - ---üäß - -for i,filter in pairs(ide.iofilters) do - if filter.input and filter.output then - assert(filter.output("",filter.input("","äöüÄÖÜß")), - "„”äöüÄÖÜß","UTF8-ANSI conversion failed: "..(i)) - end -end - --- which: "input" or "output" -function GetConfigIOFilter(which) - local filtername = ide.config.editor.iofilter - return (filtername and ide.iofilters[filtername] and ide.iofilters[filtername][which]) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/keymap.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/keymap.lua deleted file mode 100644 index 13be885..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/keymap.lua +++ /dev/null @@ -1,136 +0,0 @@ -local ide = ide - ---[[ -Accelerator general syntax is any combination of "CTRL", "ALT" and "SHIFT" -strings (case doesn't matter) separated by either '-' or '+' characters and -followed by the accelerator itself. The accelerator may be any alphanumeric -character, any function key (from F1 to F12) or one of the special characters -listed below (again, case doesn't matter): - - DEL/DELETE Delete key - INS/INSERT Insert key - ENTER/RETURN Enter key - PGUP PageUp key - PGDN PageDown key - LEFT Left cursor arrow key - RIGHT Right cursor arrow key - UP Up cursor arrow key - DOWN Down cursor arrow key - HOME Home key - END End key - SPACE Space - TAB Tab key - ESC/ESCAPE Escape key (Windows only) ---]] - -ide.config.keymap = { --- File menu - [ID.NEW] = "Ctrl-N", - [ID.OPEN] = "Ctrl-O", - [ID.CLOSE] = "Ctrl-W", - [ID.SAVE] = "Ctrl-S", - [ID.SAVEAS] = "Alt-Shift-S", - [ID.SAVEALL] = "", - [ID.RECENTFILES] = "", - [ID.RECENTFILESPREV] = "Ctrl-,", - [ID.RECENTFILESNEXT] = "Ctrl-.", - [ID.EXIT] = "Ctrl-Q", - [ID.RECENTPROJECTSPREV] = "Ctrl-Shift-<", --- Edit menu - [ID.CUT] = "Ctrl-X", - [ID.COPY] = "Ctrl-C", - [ID.PASTE] = "Ctrl-V", - [ID.SELECTALL] = "Ctrl-A", - [ID.UNDO] = "Ctrl-Z", - [ID.REDO] = "Ctrl-Y", - [ID.SHOWTOOLTIP] = "Ctrl-T", - [ID.AUTOCOMPLETE] = "Ctrl-K", - [ID.AUTOCOMPLETEENABLE] = "", - [ID.COMMENT] = "Ctrl-U", - [ID.FOLD] = "F12", - [ID.CLEARDYNAMICWORDS] = "", - [ID.REINDENT] = "Ctrl-I", - [ID.BOOKMARKTOGGLE] = "Ctrl-F2", - [ID.BOOKMARKNEXT] = "F2", - [ID.BOOKMARKPREV] = "Shift-F2", - [ID.NAVIGATETOFILE] = "Ctrl-P", - [ID.NAVIGATETOLINE] = "Ctrl-G", - [ID.NAVIGATETOSYMBOL] = "Ctrl-B", - [ID.NAVIGATETOMETHOD] = "Ctrl-;", --- Search menu - [ID.FIND] = "Ctrl-F", - [ID.FINDNEXT] = "F3", - [ID.FINDPREV] = "Shift-F3", - [ID.FINDSELECTNEXT] = "Ctrl-F3", - [ID.FINDSELECTPREV] = "Ctrl-Shift-F3", --- [ID.REPLACE] = "Ctrl-R", - [ID.FINDINFILES] = "Ctrl-Shift-F", - [ID.REPLACEINFILES] = "Ctrl-Shift-R", - [ID.SORT] = "", --- View menu - [ID.VIEWFILETREE] = "Ctrl-Shift-P", - [ID.VIEWOUTPUT] = "Ctrl-Shift-O", - [ID.VIEWWATCHWINDOW] = "Ctrl-Shift-W", - [ID.VIEWCALLSTACK] = "Ctrl-Shift-S", - [ID.VIEWDEFAULTLAYOUT] = "", - [ID.VIEWFULLSCREEN] = "Ctrl-Shift-A", - [ID.ZOOMRESET] = "Ctrl-0", - [ID.ZOOMIN] = "Ctrl-+", - [ID.ZOOMOUT] = "Ctrl--", --- Project menu - [ID.RUN] = "F6", - [ID.RUNNOW] = "Ctrl-F6", - [ID.COMPILE] = "F7", - [ID.ANALYZE] = "Shift-F7", - [ID.STARTDEBUG] = "F5", - [ID.ATTACHDEBUG] = "", - [ID.DETACHDEBUG] = "", - [ID.STOPDEBUG] = "Shift-F5", - [ID.STEP] = "F10", - [ID.STEPOVER] = "Shift-F10", - [ID.STEPOUT] = "Ctrl-F10", - [ID.RUNTO] = "Ctrl-Shift-F10", - [ID.TRACE] = "", - [ID.BREAK] = "", - [ID.BREAKPOINTTOGGLE] = "Ctrl-F9", - [ID.BREAKPOINTNEXT] = "F9", - [ID.BREAKPOINTPREV] = "Shift-F9", - [ID.CLEAROUTPUT] = "", - [ID.INTERPRETER] = "", - [ID.PROJECTDIR] = "", --- Help menu - [ID.ABOUT] = "F1", --- Watch window menu items - [ID.ADDWATCH] = "Ins", - [ID.EDITWATCH] = "F2", - [ID.DELETEWATCH] = "Del", --- Editor popup menu items - [ID.QUICKADDWATCH] = "", - [ID.QUICKEVAL] = "", --- Filetree popup menu items - [ID.RENAMEFILE] = "F2", - [ID.DELETEFILE] = "Del", -} - -function KSC(id, default) - -- this is only for the rare case of someone assigning a complete list - -- to ide.config.keymap. - local keymap = ide.config.keymap - return (keymap[id] and "\t"..keymap[id]) or (default and "\t"..default) or "" -end - -ide.config.editor.keymap = { - -- key, modifier, command, os: http://www.scintilla.org/ScintillaDoc.html#KeyboardCommands - -- Cmd+Left/Right moves to start/end of line - {wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_HOME, "Macintosh"}, - {wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_LINEEND, "Macintosh"}, - -- Cmd+Shift+Left/Right selects to the beginning/end of the line - {wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_HOMEEXTEND, "Macintosh"}, - {wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEENDEXTEND, "Macintosh"}, - -- Cmd+Shift+Up/Down selects to the beginning/end of the text - {wxstc.wxSTC_KEY_UP, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEUPEXTEND, "Macintosh"}, - {wxstc.wxSTC_KEY_DOWN, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEDOWNEXTEND, "Macintosh"}, - -- Opt+Left/Right moves one word left (to the beginning)/right (to the end) - {wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_ALT, wxstc.wxSTC_CMD_WORDLEFT, "Macintosh"}, - {wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_ALT, wxstc.wxSTC_CMD_WORDRIGHTEND, "Macintosh"}, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markers.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markers.lua deleted file mode 100644 index 0708f4c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markers.lua +++ /dev/null @@ -1,247 +0,0 @@ --- Copyright 2015 Paul Kulchenko, ZeroBrane LLC - -local ide = ide -ide.markers = { - markersCtrl = nil, - imglist = ide:CreateImageList("MARKERS", "FILE-NORMAL", "DEBUG-BREAKPOINT-TOGGLE", "BOOKMARK-TOGGLE"), - needrefresh = {}, - settings = {markers = {}}, -} - -local unpack = table.unpack or unpack -local markers = ide.markers -local caches = {} -local image = { FILE = 0, BREAKPOINT = 1, BOOKMARK = 2 } -local markertypes = {breakpoint = 0, bookmark = 0} -local maskall = 0 -for markertype in pairs(markertypes) do - markertypes[markertype] = 2^ide:GetMarker(markertype) - maskall = maskall + markertypes[markertype] -end - -local function resetMarkersTimer() - if ide.config.markersinactivity then - ide.timers.markers:Start(ide.config.markersinactivity*1000, wx.wxTIMER_ONE_SHOT) - end -end - -local function needRefresh(editor) - ide.markers.needrefresh[editor] = true - resetMarkersTimer() -end - -local function getMarkers(editor) - local edmarkers = {} - local line = editor:MarkerNext(0, maskall) - while line > -1 do - local markerval = editor:MarkerGet(line) - for markertype, val in pairs(markertypes) do - if bit.band(markerval, val) > 0 then - table.insert(edmarkers, {line, markertype}) - end - end - line = editor:MarkerNext(line + 1, maskall) - end - return edmarkers -end - -local function markersRefresh() - local ctrl = ide.markers.markersCtrl - local win = ide:GetMainFrame():FindFocus() - ctrl:Freeze() - - for editor in pairs(ide.markers.needrefresh) do - local cache = caches[editor] - if cache then - local fileitem = cache.fileitem - if not fileitem then - local filename = ide:GetDocument(editor):GetTabText() - local root = ctrl:GetRootItem() - if not root or not root:IsOk() then return end - fileitem = ctrl:AppendItem(root, filename, image.FILE) - ctrl:SortChildren(root) - cache.fileitem = fileitem - end - - -- disabling event handlers is not strictly necessary, but it's expected - -- to fix a crash on Windows that had DeleteChildren in the trace (#442). - ctrl:SetEvtHandlerEnabled(false) - ctrl:DeleteChildren(fileitem) - ctrl:SetEvtHandlerEnabled(true) - - for _, edmarker in ipairs(getMarkers(editor)) do - local line, markertype = unpack(edmarker) - local text = ("%d: %s"):format(line+1, FixUTF8(editor:GetLineDyn(line))) - ctrl:AppendItem(fileitem, text:gsub("[\r\n]+$",""), image[markertype:upper()]) - end - - -- if no markers added, then remove the file from the markers list - ctrl:Expand(fileitem) - if not ctrl:ItemHasChildren(fileitem) then - ctrl:Delete(fileitem) - cache.fileitem = nil - end - end - end - - ctrl:Thaw() - if win and win ~= ide:GetMainFrame():FindFocus() then win:SetFocus() end -end - -local function item2editor(item_id) - for editor, cache in pairs(caches) do - if cache.fileitem and cache.fileitem:GetValue() == item_id:GetValue() then return editor end - end -end - -local function createMarkersWindow() - local width, height = 360, 200 - local ctrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(width, height), - wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_HIDE_ROOT + wx.wxNO_BORDER) - - markers.markersCtrl = ctrl - ide.timers.markers = wx.wxTimer(ctrl) - - ctrl:AddRoot("Markers") - ctrl:SetImageList(markers.imglist) - ctrl:SetFont(ide.font.fNormal) - - function ctrl:ActivateItem(item_id, toggle) - local itemimage = ctrl:GetItemImage(item_id) - if itemimage == image.FILE then - -- activate editor tab - local editor = item2editor(item_id) - if editor then ide:GetDocument(editor):SetActive() end - else -- clicked on the marker item - local parent = ctrl:GetItemParent(item_id) - if parent:IsOk() and ctrl:GetItemImage(parent) == image.FILE then - local editor = item2editor(parent) - if editor then - local line = tonumber(ctrl:GetItemText(item_id):match("^(%d+):")) - if line then - if toggle then - local _ = (itemimage == image.BOOKMARK and editor:BookmarkToggle(line-1, false) - or itemimage == image.BREAKPOINT and editor:BreakpointToggle(line-1, false)) - ctrl:Delete(item_id) - return -- don't activate the editor when the breakpoint is toggled - end - editor:GotoLine(line-1) - end - ide:GetDocument(editor):SetActive() - end - end - end - end - - local function activateByPosition(event) - local mask = (wx.wxTREE_HITTEST_ONITEMINDENT + wx.wxTREE_HITTEST_ONITEMLABEL - + wx.wxTREE_HITTEST_ONITEMICON + wx.wxTREE_HITTEST_ONITEMRIGHT) - local item_id, flags = ctrl:HitTest(event:GetPosition()) - - if item_id and item_id:IsOk() and bit.band(flags, mask) > 0 then - ctrl:ActivateItem(item_id, bit.band(flags, wx.wxTREE_HITTEST_ONITEMICON) > 0) - else - event:Skip() - end - return true - end - - ctrl:Connect(wx.wxEVT_TIMER, function() markersRefresh() end) - ctrl:Connect(wx.wxEVT_LEFT_DOWN, activateByPosition) - ctrl:Connect(wx.wxEVT_LEFT_DCLICK, activateByPosition) - ctrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED, function(event) - ctrl:ActivateItem(event:GetItem()) - end) - - ctrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_MENU, - function (event) - local item_id = event:GetItem() - local ID_BOOKMARKTOGGLE = ID("markers.bookmarktoggle") - local ID_BREAKPOINTTOGGLE = ID("markers.breakpointtoggle") - local menu = wx.wxMenu { - { ID_BOOKMARKTOGGLE, TR("Toggle Bookmark"), TR("Toggle bookmark") }, - { ID_BREAKPOINTTOGGLE, TR("Toggle Breakpoint"), TR("Toggle breakpoint") }, - } - local activate = function() ctrl:ActivateItem(item_id, true) end - menu:Enable(ID_BOOKMARKTOGGLE, ctrl:GetItemImage(item_id) == image.BOOKMARK) - menu:Connect(ID_BOOKMARKTOGGLE, wx.wxEVT_COMMAND_MENU_SELECTED, activate) - - menu:Enable(ID_BREAKPOINTTOGGLE, ctrl:GetItemImage(item_id) == image.BREAKPOINT) - menu:Connect(ID_BREAKPOINTTOGGLE, wx.wxEVT_COMMAND_MENU_SELECTED, activate) - - PackageEventHandle("onMenuMarkers", menu, ctrl, event) - - ctrl:PopupMenu(menu) - end) - - local function reconfigure(pane) - pane:TopDockable(false):BottomDockable(false) - :MinSize(150,-1):BestSize(300,-1):FloatingSize(200,300) - end - - local layout = ide:GetSetting("/view", "uimgrlayout") - if not layout or not layout:find("markerspanel") then - ide:AddPanelDocked(ide:GetOutputNotebook(), ctrl, "markerspanel", TR("Markers"), reconfigure, false) - else - ide:AddPanel(ctrl, "markerspanel", TR("Markers"), reconfigure) - end -end - -createMarkersWindow() - -local package = ide:AddPackage('core.markers', { - -- save markers; remove tab from the list - onEditorClose = function(self, editor) - local cache = caches[editor] - if not cache then return end - if cache.fileitem then markers.markersCtrl:Delete(cache.fileitem) end - caches[editor] = nil - end, - - -- schedule marker update if the change is for one of the editors with markers - onEditorUpdateUI = function(self, editor, event) - if not caches[editor] then return end - if bit.band(event:GetUpdated(), wxstc.wxSTC_UPDATE_CONTENT) == 0 then return end - needRefresh(editor) - end, - - onEditorMarkerUpdate = function(self, editor) - -- if no marker, then all markers in a file need to be refreshed - if not caches[editor] then caches[editor] = {} end - needRefresh(editor) - markers:SaveMarkers(editor) - end, - - onEditorSave = function(self, editor) markers:SaveMarkers(editor) end, - onEditorLoad = function(self, editor) markers:LoadMarkers(editor) end, - }) - -function markers:SaveSettings() package:SetSettings(self.settings) end - -function markers:SaveMarkers(editor, force) - -- if the file has the name and has not been modified, save the breakpoints - -- this also works when the file is saved as the modified flag is already set to `false` - local doc = ide:GetDocument(editor) - local filepath = doc:GetFilePath() - if filepath and (force or not doc:IsModified()) then - -- remove it from the list if it has no breakpoints - local edmarkers = getMarkers(editor) - self.settings.markers[filepath] = #edmarkers > 0 and edmarkers or nil - self:SaveSettings() - end -end - -function markers:LoadMarkers(editor) - local doc = ide:GetDocument(editor) - local filepath = doc:GetFilePath() - if filepath then - for _, edmarker in ipairs(self.settings.markers[filepath] or {}) do - local line, markertype = unpack(edmarker) - local _ = (markertype == "bookmark" and editor:BookmarkToggle(line, true) - or markertype == "breakpoint" and editor:BreakpointToggle(line, true)) - end - end -end - -MergeSettings(markers.settings, package:GetSettings()) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markup.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markup.lua deleted file mode 100644 index 420543d..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/markup.lua +++ /dev/null @@ -1,214 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- styles for comment markup ---------------------------------------------------------- - -local MD_MARK_ITAL = '_' -- italic -local MD_MARK_BOLD = '**' -- bold -local MD_MARK_LINK = '[' -- link description start -local MD_MARK_LINZ = ']' -- link description end -local MD_MARK_LINA = '(' -- link URL start -local MD_MARK_LINT = ')' -- link URL end -local MD_MARK_HEAD = '#' -- header -local MD_MARK_CODE = '`' -- code -local MD_MARK_BOXD = '|' -- highlight -local MD_MARK_MARK = ' ' -- separator -local MD_LINK_NEWWINDOW = '+' -- indicator to open a new window for links -local markup = { - [MD_MARK_BOXD] = {st=ide:AddIndicator("markup.boxd", 25), fg={127,0,127}, b=true}, - [MD_MARK_CODE] = {st=ide:AddIndicator("markup.code", 26), fg={127,127,127}, fs=10}, - [MD_MARK_HEAD] = {st=ide:AddIndicator("markup.head", 27), fn="Lucida Console", b=true}, - [MD_MARK_LINK] = {st=ide:AddIndicator("markup.link", 28), u=true, hs={32,32,127}}, - [MD_MARK_BOLD] = {st=ide:AddIndicator("markup.bold", 29), b=true}, - [MD_MARK_ITAL] = {st=ide:AddIndicator("markup.ital", 30), i=true}, - [MD_MARK_MARK] = {st=ide:AddIndicator("markup.mark", 31), v=false}, -} - --- allow other editor features to recognize this special markup -function MarkupIsSpecial(style) return style == 31 end -function MarkupIsAny(style) return style >= 25 and style <= 31 end -function MarkupAddStyles(styles) - local comment = styles.comment or {} - for key,value in pairs(markup) do - local style = styles[key] or {} - -- copy all style features by value - for feature in pairs(value) do - style[feature] = style[feature] or value[feature] - end - style.fg = style.fg or comment.fg - style.bg = style.bg or comment.bg - styles[key] = style - end -end - -local q = EscapeMagic - -local MD_MARK_PTRN = '' -- combination of all markup marks that can start styling -for key in pairs(markup) do - if key ~= MD_MARK_MARK then MD_MARK_PTRN = MD_MARK_PTRN .. q(key) end -end -MarkupAddStyles(ide.config.styles) - -function MarkupHotspotClick(pos, editor) - -- check if this is "our" hotspot event - if bit.band(editor:GetStyleAt(pos),31) ~= markup[MD_MARK_LINK].st then - -- not "our" style, so nothing to do for us here - return - end - local line = editor:LineFromPosition(pos) - local tx = editor:GetLineDyn(line) - pos = pos + #MD_MARK_LINK - editor:PositionFromLine(line) -- turn into relative position - - -- extract the URL/command on the right side of the separator - local _,_,text = string.find(tx, q(MD_MARK_LINZ).."(%b"..MD_MARK_LINA..MD_MARK_LINT..")", pos) - if text then - text = text:gsub("^"..q(MD_MARK_LINA), ""):gsub(q(MD_MARK_LINT).."$", "") - local doc = ide:GetDocument(editor) - local filepath = doc and doc.filePath or FileTreeGetDir() - local _,_,http = string.find(text, [[^(https?:%S+)$]]) - local _,_,command,code = string.find(text, [[^macro:(%w+)%((.*%S)%)$]]) - if not command then _,_,command = string.find(text, [[^macro:(%w+)$]]) end - - if command == 'shell' then - ShellExecuteCode(code) - elseif command == 'inline' then - ShellExecuteInline(code) - elseif command == 'run' then -- run the current file - ProjectRun() - elseif command == 'debug' then -- debug the current file - ProjectDebug() - elseif http then -- open the URL in a new browser window - wx.wxLaunchDefaultBrowser(http, 0) - elseif filepath then -- only check for saved files - -- check if requested to open in a new window - local newwindow = not doc or string.find(text, MD_LINK_NEWWINDOW, 1, true) - if newwindow then text = string.gsub(text, "^%" .. MD_LINK_NEWWINDOW, "") end - local filename = GetFullPathIfExists( - wx.wxFileName(filepath):GetPath(wx.wxPATH_GET_VOLUME), text) - if filename and - (newwindow or SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL) then - if not newwindow and ide.osname == 'Macintosh' then editor:GotoPos(0) end - LoadFile(filename,not newwindow and editor or nil,true) - end - end - end - return true -end - -local function ismarkup (tx) - local start = 1 - local marksep = "[%s!%?%.,;:%(%)]" - while true do - -- find a separator first - local st,_,sep,more = string.find(tx, "(["..MD_MARK_PTRN.."])(.)", start) - if not st then return end - - -- check if this is a first character of a multi-character separator - if not markup[sep] then sep = sep .. (more or '') end - - local s,e,cap - local qsep = q(sep) - local nonsep = ("[^%s]"):format(qsep) - local nonspace = ("[^%s]"):format(qsep.."%s") - if sep == MD_MARK_HEAD then - -- always search from the start of the line - -- [%w%p] set is needed to avoid continuing this markup to the next line - s,e,cap = string.find(tx,"^("..q(MD_MARK_HEAD)..".+[%w%p])") - elseif sep == MD_MARK_LINK then - -- allow everything based on balanced link separators - s,e,cap = string.find(tx, - "^(%b"..MD_MARK_LINK..MD_MARK_LINZ - .."%b"..MD_MARK_LINA..MD_MARK_LINT..")", st) - elseif markup[sep] then - -- try 2+ characters between separators first - -- if not found, try a single character - s,e,cap = string.find(tx,"^("..qsep..nonspace..nonsep.."-"..nonspace..qsep..")", st) - if not s then s,e,cap = string.find(tx,"^("..qsep..nonspace..qsep..")", st) end - end - if s and -- selected markup is surrounded by spaces or punctuation marks - (s == 1 or tx:sub(s-1, s-1):match(marksep)) and - (e == #tx or tx:sub(e+1, e+1):match(marksep)) - then return s,e,cap,sep end - start = st+1 - end -end - -function MarkupStyle(editor, lines, linee) - local lines = lines or 0 - if (lines < 0) then return end - - -- if the current spec doesn't have any comments, nothing to style - if not next(editor.spec.iscomment) then return end - - -- always style to the end as there may be comments that need re-styling - -- technically, this should be GetLineCount()-1, but we want to style - -- beyond the last line to make sure it is styled correctly - local linec = editor:GetLineCount() - local linee = linee or linec - - local linecomment = editor.spec.linecomment - local iscomment = {} - for i,v in pairs(editor.spec.iscomment) do - iscomment[i] = v - end - - local es = editor:GetEndStyled() - local needfix = false - - for line=lines,linee do - local tx = editor:GetLineDyn(line) - local ls = editor:PositionFromLine(line) - - local from = 1 - local off = -1 - - -- doing WrapCount(line) when line == linec (which may be beyond - -- the last line) occasionally crashes the application on OSX. - local wrapped = line < linec and editor:WrapCount(line) or 0 - - while from do - tx = string.sub(tx,from) - local f,t,w,mark = ismarkup(tx) - - if (f) then - local p = ls+f+off - local s = bit.band(editor:GetStyleAt(p), 31) - -- only style comments and only those that are not at the beginning - -- of the file to avoid styling shebang (#!) lines - -- also ignore matches for line comments (as defined in the spec) - if iscomment[s] and p > 0 and mark ~= linecomment then - local smark = #mark - local emark = #mark -- assumes end mark is the same length as start mark - if mark == MD_MARK_HEAD then - -- grab multiple MD_MARK_HEAD if present - local _,_,full = string.find(w,"^("..q(MD_MARK_HEAD).."+)") - smark,emark = #full,0 - elseif mark == MD_MARK_LINK then - local lsep = w:find(q(MD_MARK_LINZ)..q(MD_MARK_LINA)) - if lsep then emark = #w-lsep+#MD_MARK_LINT end - end - editor:StartStyling(p, 31) - editor:SetStyling(smark, markup[MD_MARK_MARK].st) - editor:SetStyling(t-f+1-smark-emark, markup[mark].st or markup[MD_MARK_MARK].st) - editor:SetStyling(emark, markup[MD_MARK_MARK].st) - end - - off = off + t - end - from = t and (t+1) - end - - -- has this line changed its wrapping because of invisible styling? - if wrapped > 1 and editor:WrapCount(line) < wrapped then needfix = true end - end - editor:StartStyling(es, 31) - - -- if any wrapped lines have changed, then reset WrapMode to fix the drawing - if needfix then - -- this fixes an issue with duplicate lines in Scintilla when - -- invisible styles hide some of the content that would be wrapped. - local wrapmode = editor:GetWrapMode() - if wrapmode ~= wxstc.wxSTC_WRAP_NONE then editor:SetWrapMode(wrapmode) end - -- if some of the lines have folded, this can make not styled lines visible - MarkupStyle(editor, linee+1) -- style to the end in this case - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_edit.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_edit.lua deleted file mode 100644 index d095f6e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_edit.lua +++ /dev/null @@ -1,390 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide - --- --------------------------------------------------------------------------- --- Create the Edit menu and attach the callback functions - -local frame = ide.frame -local menuBar = frame.menuBar - -local editMenu = wx.wxMenu { - { ID_CUT, TR("Cu&t")..KSC(ID_CUT), TR("Cut selected text to clipboard") }, - { ID_COPY, TR("&Copy")..KSC(ID_COPY), TR("Copy selected text to clipboard") }, - { ID_PASTE, TR("&Paste")..KSC(ID_PASTE), TR("Paste text from the clipboard") }, - { ID_SELECTALL, TR("Select &All")..KSC(ID_SELECTALL), TR("Select all text in the editor") }, - { }, - { ID_UNDO, TR("&Undo")..KSC(ID_UNDO), TR("Undo last edit") }, - { ID_REDO, TR("&Redo")..KSC(ID_REDO), TR("Redo last edit undone") }, - { }, - { ID_SHOWTOOLTIP, TR("Show &Tooltip")..KSC(ID_SHOWTOOLTIP), TR("Show tooltip for current position; place cursor after opening bracket of function") }, - { ID_AUTOCOMPLETE, TR("Complete &Identifier")..KSC(ID_AUTOCOMPLETE), TR("Complete the current identifier") }, - { ID_AUTOCOMPLETEENABLE, TR("Auto Complete Identifiers")..KSC(ID_AUTOCOMPLETEENABLE), TR("Auto complete while typing"), wx.wxITEM_CHECK }, - { }, -} - -editMenu:Append(ID_SOURCE, TR("Source"), wx.wxMenu { - { ID_COMMENT, TR("C&omment/Uncomment")..KSC(ID_COMMENT), TR("Comment or uncomment current or selected lines") }, - { ID_REINDENT, TR("Correct &Indentation")..KSC(ID_REINDENT), TR("Re-indent selected lines") }, - { ID_FOLD, TR("&Fold/Unfold All")..KSC(ID_FOLD), TR("Fold or unfold all code folds") }, - { ID_SORT, TR("&Sort")..KSC(ID_SORT), TR("Sort selected lines") }, -}) -editMenu:Append(ID_BOOKMARK, TR("Bookmark"), wx.wxMenu { - { ID_BOOKMARKTOGGLE, TR("Toggle Bookmark")..KSC(ID_BOOKMARKTOGGLE), TR("Toggle bookmark") }, - { ID_BOOKMARKNEXT, TR("Go To Next Bookmark")..KSC(ID_BOOKMARKNEXT) }, - { ID_BOOKMARKPREV, TR("Go To Previous Bookmark")..KSC(ID_BOOKMARKPREV) }, -}) -editMenu:AppendSeparator() -editMenu:Append(ID_PREFERENCES, TR("Preferences"), wx.wxMenu { - { ID_PREFERENCESSYSTEM, TR("Settings: System")..KSC(ID_PREFERENCESSYSTEM) }, - { ID_PREFERENCESUSER, TR("Settings: User")..KSC(ID_PREFERENCESUSER) }, -}) -menuBar:Append(editMenu, TR("&Edit")) - -editMenu:Check(ID_AUTOCOMPLETEENABLE, ide.config.autocomplete) - -local function getCtrlWithFocus(edType) - local ctrl = ide:GetMainFrame():FindFocus() - return ctrl and ctrl:GetClassInfo():GetClassName() == edType and ctrl:DynamicCast(edType) or nil -end - -local function onUpdateUIEditorInFocus(event) - event:Enable(GetEditorWithFocus(GetEditor()) ~= nil) -end - -local function onUpdateUIEditMenu(event) - local menu_id = event:GetId() - local editor = GetEditorWithFocus() - if editor == nil then - local editor = getCtrlWithFocus("wxTextCtrl") - event:Enable(editor and ( - menu_id == ID_PASTE and editor:CanPaste() or - menu_id == ID_UNDO and editor:CanUndo() or - menu_id == ID_REDO and editor:CanRedo() or - menu_id == ID_CUT and editor:CanCut() or - menu_id == ID_COPY and editor:CanCopy() or - menu_id == ID_SELECTALL and true - ) or false) - return - end - - local alwaysOn = { - [ID_SELECTALL] = true, - -- allow Cut and Copy commands as these work on a line if no selection - [ID_COPY] = true, [ID_CUT] = true, - } - local enable = - -- pasting is allowed when the document is not read-only and the selection - -- (if any) has no protected text; since pasting handles protected text, - -- use GetReadOnly() instead of CanPaste() - menu_id == ID_PASTE and (not editor:GetReadOnly()) or - menu_id == ID_UNDO and editor:CanUndo() or - menu_id == ID_REDO and editor:CanRedo() or - alwaysOn[menu_id] - event:Enable(enable) -end - -local function onEditMenu(event) - local menu_id = event:GetId() - local editor = GetEditorWithFocus() - if editor == nil then - local editor = getCtrlWithFocus("wxTextCtrl") - if not editor or not ( - menu_id == ID_PASTE and editor:Paste() or - menu_id == ID_UNDO and editor:Undo() or - menu_id == ID_REDO and editor:Redo() or - menu_id == ID_CUT and editor:Cut() or - menu_id == ID_COPY and editor:Copy() or - menu_id == ID_SELECTALL and editor:SetSelection(-1, -1) or - true - ) then event:Skip() end - return - end - - if PackageEventHandle("onEditorAction", editor, event) == false then - return - end - - local copytext - if (menu_id == ID_CUT or menu_id == ID_COPY) - and ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then - local main = editor:GetMainSelection() - copytext = editor:GetTextRangeDyn(editor:GetSelectionNStart(main), editor:GetSelectionNEnd(main)) - for s = 0, editor:GetSelections()-1 do - if copytext ~= editor:GetTextRangeDyn(editor:GetSelectionNStart(s), editor:GetSelectionNEnd(s)) then - copytext = nil - break - end - end - end - - local spos, epos = editor:GetSelectionStart(), editor:GetSelectionEnd() - if menu_id == ID_CUT then - if spos == epos then editor:LineCopy() else editor:CopyDyn() end - if spos == epos then - local line = editor:LineFromPosition(spos) - spos, epos = editor:PositionFromLine(line), editor:PositionFromLine(line+1) - editor:SetSelectionStart(spos) - editor:SetSelectionEnd(epos) - end - if spos ~= epos then editor:ClearAny() end - elseif menu_id == ID_COPY then - if spos == epos then editor:LineCopy() else editor:CopyDyn() end - elseif menu_id == ID_PASTE then - -- first clear the text in case there is any hidden markup - if spos ~= epos then editor:ClearAny() end - editor:PasteDyn() - elseif menu_id == ID_SELECTALL then editor:SelectAll() - elseif menu_id == ID_UNDO then editor:Undo() - elseif menu_id == ID_REDO then editor:Redo() - end - - if copytext then editor:CopyText(#copytext, copytext) end -end - -for _, event in pairs({ID_CUT, ID_COPY, ID_PASTE, ID_SELECTALL, ID_UNDO, ID_REDO}) do - frame:Connect(event, wx.wxEVT_COMMAND_MENU_SELECTED, onEditMenu) - frame:Connect(event, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu) -end - -for _, event in pairs({ - ID_BOOKMARKTOGGLE, ID_BOOKMARKNEXT, ID_BOOKMARKPREV, - ID_AUTOCOMPLETE, ID_SORT, ID_REINDENT, ID_SHOWTOOLTIP, -}) do - frame:Connect(event, wx.wxEVT_UPDATE_UI, onUpdateUIEditorInFocus) -end - -frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, - function(event) - local editor = GetEditorWithFocus(GetEditor()) - event:Enable(editor ~= nil - and ide:IsValidProperty(editor, "spec") and editor.spec - and editor.spec.linecomment and true or false) - end) - -local function generateConfigMessage(type) - return ([==[--[[-- - Use this file to specify **%s** preferences. - Review [examples](+%s) or check [online documentation](%s) for details. ---]]-- -]==]) - :format(type, MergeFullPath(ide.editorFilename, "../cfg/user-sample.lua"), - "http://studio.zerobrane.com/documentation.html") -end - -frame:Connect(ID_PREFERENCESSYSTEM, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - local editor = LoadFile(ide.configs.system) - if editor and editor:GetLength() == 0 then - editor:AddTextDyn(generateConfigMessage("System")) end - end) - -frame:Connect(ID_PREFERENCESUSER, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - local editor = LoadFile(ide.configs.user) - if editor and editor:GetLength() == 0 then - editor:AddTextDyn(generateConfigMessage("User")) end - end) -frame:Connect(ID_PREFERENCESUSER, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(ide.configs.user ~= nil) end) - -frame:Connect(ID_CLEARDYNAMICWORDS, wx.wxEVT_COMMAND_MENU_SELECTED, - function () DynamicWordsReset() end) - -frame:Connect(ID_SHOWTOOLTIP, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - - if (editor:CallTipActive()) then - editor:CallTipCancel() - return - end - - EditorCallTip(editor, editor:GetCurrentPos()) - end) - -frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) EditorAutoComplete(GetEditor()) end) - -frame:Connect(ID_AUTOCOMPLETEENABLE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) ide.config.autocomplete = event:IsChecked() end) - -frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - local lc = editor.spec.linecomment - if not lc then return end - - -- for multi-line selection, always start the first line at the beginning - local ssel, esel = editor:GetSelectionStart(), editor:GetSelectionEnd() - local sline = editor:LineFromPosition(ssel) - local eline = editor:LineFromPosition(esel) - local sel = ssel ~= esel - local rect = editor:SelectionIsRectangle() - local qlc = lc:gsub(".", "%%%1") - - -- figure out how to toggle comments; if there is at least one non-empty - -- line that doesn't start with a comment, need to comment - local comment = false - for line = sline, eline do - local pos = sel and (sline == eline or rect) - and ssel-editor:PositionFromLine(sline)+1 or 1 - local text = editor:GetLineDyn(line) - local _, cpos = text:find("^%s*"..qlc, pos) - if not cpos and text:find("%S") - -- ignore last line when the end of selection is at the first position - and (line == sline or line < eline or esel-editor:PositionFromLine(line) > 0) then - comment = true - break - end - end - - editor:BeginUndoAction() - -- go last to first as selection positions we captured may be affected - -- by text changes - for line = eline, sline, -1 do - local pos = sel and (sline == eline or rect) and ssel-editor:PositionFromLine(sline)+1 or 1 - local text = editor:GetLineDyn(line) - local validline = (line == sline or line < eline or esel-editor:PositionFromLine(line) > 0) - local _, cpos = text:find("^%s*"..qlc, pos) - if not comment and cpos and validline then - editor:DeleteRange(cpos-#lc+editor:PositionFromLine(line), #lc) - elseif comment and text:find("%S") and validline then - editor:SetTargetStart(pos+editor:PositionFromLine(line)-1) - editor:SetTargetEnd(editor:GetTargetStart()) - editor:ReplaceTarget(lc) - end - end - editor:EndUndoAction() - end) - -local function processSelection(editor, func) - local text = editor:GetSelectedText() - local line = editor:GetCurrentLine() - local posinline = editor:GetCurrentPos() - editor:PositionFromLine(line) - if #text == 0 then - editor:SelectAll() - text = editor:GetSelectedText() - end - local wholeline = text:find("\n$") - local buf = {} - for line in string.gmatch(text..(wholeline and "" or "\n"), "(.-\r?\n)") do - table.insert(buf, line) - end - if #buf > 0 then - if func then func(buf) end - -- add new line at the end if it was there - local newtext = table.concat(buf, ""):gsub("(\r?\n)$", wholeline and "%1" or "") - -- straightforward editor:ReplaceSelection() doesn't work reliably as - -- it sometimes doubles the context when the entire file is selected. - -- this seems like Scintilla issue, so use ReplaceTarget instead. - -- Since this doesn't work with rectangular selection, which - -- ReplaceSelection should handle (after wxwidgets 3.x upgrade), this - -- will need to be revisited when ReplaceSelection is updated. - if newtext ~= text then - editor:BeginUndoAction() - -- if there is at least one marker, then use a different mechanism to preserve them - -- simply saving markers, replacing text, and reapplying markers doesn't work as - -- they get reset after `undo/redo` operations. - local ssel, esel = editor:GetSelectionStart(), editor:GetSelectionEnd() - local sline = editor:LineFromPosition(ssel) - local eline = editor:LineFromPosition(esel) - if #editor:MarkerGetAll(nil, sline, eline) > 0 then - for line = #buf, 1, -1 do - editor:SetTargetStart(line == 1 and ssel or editor:PositionFromLine(sline+line-1)) - editor:SetTargetEnd(line == eline-sline+1 and esel or editor:GetLineEndPosition(sline+line-1)) - editor:ReplaceTarget((buf[line]:gsub("\r?\n$", ""))) - end - else - editor:TargetFromSelection() - editor:ReplaceTarget(newtext) - end - editor:EndUndoAction() - end - end - editor:GotoPosEnforcePolicy(math.min( - editor:PositionFromLine(line)+posinline, editor:GetLineEndPosition(line))) -end - -frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) processSelection(GetEditor(), table.sort) end) - -local function reIndent(editor, buf) - local decindent, incindent = editor.spec.isdecindent, editor.spec.isincindent - if not (decindent and incindent) then return end - - local edline = editor:LineFromPosition(editor:GetSelectionStart()) - local indent = 0 - local text = "" - -- find the last non-empty line in the previous block (if any) - for n = edline-1, 1, -1 do - indent = editor:GetLineIndentation(n) - text = editor:GetLineDyn(n) - if text:match("[^\r\n]") then break end - end - - local ut = editor:GetUseTabs() - local tw = ut and editor:GetTabWidth() or editor:GetIndent() - - local indents = {} - local isstatic = {} - for line = 1, #buf+1 do - local ls = editor:PositionFromLine(edline+line-1) - local style = bit.band(editor:GetStyleAt(ls), 31) - -- don't reformat multi-line comments or strings - isstatic[line] = (editor.spec.iscomment[style] - or editor.spec.isstring[style] - or (MarkupIsAny and MarkupIsAny(style))) - if not isstatic[line] or line == 1 or not isstatic[line-1] then - local closed, blockend = decindent(text) - local opened = incindent(text) - - -- ignore impact from initial block endings as they are already indented - if line == 1 then blockend = 0 end - - -- this only needs to be done for 2, #buf+1; do it and get out when done - if line > 1 then indents[line-1] = indents[line-1] - tw * closed end - if line > #buf then break end - - indent = indent + tw * (opened - blockend) - if indent < 0 then indent = 0 end - end - - indents[line] = indent - text = buf[line] - end - - for line = 1, #buf do - if not isstatic[line] then - buf[line] = buf[line]:gsub("^[ \t]*", - not buf[line]:match("%S") and "" - or ut and ("\t"):rep(indents[line] / tw) or (" "):rep(indents[line])) - end - end -end - -frame:Connect(ID_REINDENT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - processSelection(editor, function(buf) reIndent(editor, buf) end) - end) - -frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, - function(event) - local editor = GetEditorWithFocus() - event:Enable(editor and editor:CanFold() or false) - end) -frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) GetEditorWithFocus():FoldSome() end) - -local BOOKMARK_MARKER = StylesGetMarker("bookmark") - -frame:Connect(ID_BOOKMARKTOGGLE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() GetEditor():BookmarkToggle() end) -frame:Connect(ID_BOOKMARKNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, - function() GetEditor():MarkerGotoNext(BOOKMARK_MARKER) end) -frame:Connect(ID_BOOKMARKPREV, wx.wxEVT_COMMAND_MENU_SELECTED, - function() GetEditor():MarkerGotoPrev(BOOKMARK_MARKER) end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_file.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_file.lua deleted file mode 100644 index d9e7c68..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_file.lua +++ /dev/null @@ -1,262 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local menuBar = frame.menuBar -local openDocuments = ide.openDocuments - -local fileMenu = wx.wxMenu({ - { ID_NEW, TR("&New")..KSC(ID_NEW), TR("Create an empty document") }, - { ID_OPEN, TR("&Open...")..KSC(ID_OPEN), TR("Open an existing document") }, - { ID_CLOSE, TR("&Close Page")..KSC(ID_CLOSE), TR("Close the current editor window") }, - { }, - { ID_SAVE, TR("&Save")..KSC(ID_SAVE), TR("Save the current document") }, - { ID_SAVEAS, TR("Save &As...")..KSC(ID_SAVEAS), TR("Save the current document to a file with a new name") }, - { ID_SAVEALL, TR("Save A&ll")..KSC(ID_SAVEALL), TR("Save all open documents") }, - { }, - { ID_RECENTFILES, TR("Recent Files")..KSC(ID_RECENTFILES), TR("File history") }, - { ID_RECENTPROJECTS, TR("Recent Projects")..KSC(ID_RECENTPROJECTS), TR("Project history") }, - { }, - { ID_EXIT, TR("E&xit")..KSC(ID_EXIT), TR("Exit program") }}) -menuBar:Append(fileMenu, TR("&File")) - -local filehistorymenu = wx.wxMenu({ - { }, - { ID_RECENTFILESCLEAR, TR("Clear Items")..KSC(ID_RECENTFILESCLEAR), TR("Clear items from this list") }, -}) -local projecthistorymenu = wx.wxMenu({ - { }, - { ID_RECENTPROJECTSCLEAR, TR("Clear Items")..KSC(ID_RECENTPROJECTSCLEAR), TR("Clear items from this list") }, -}) -ide:AttachMenu(ID_RECENTFILES, filehistorymenu) -ide:AttachMenu(ID_RECENTPROJECTS, projecthistorymenu) - -do -- recent file history - local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a")) - local function isSameAs(f1, f2) - return f1 == f2 or iscaseinsensitive and f1:lower() == f2:lower() - end - - local filehistory = {[0] = 1} - - -- add file to the file history removing duplicates - local function addFileHistory(filename) - -- a new (empty) tab is opened; don't change the history - if not filename then return end - - local fn = wx.wxFileName(filename) - if fn:Normalize() then filename = fn:GetFullPath() end - - local index = filehistory[0] - - -- special case: selecting the current file (or moving through the history) - if filehistory[index] and isSameAs(filename, filehistory[index].filename) then return end - - -- something else is selected - -- (1) flip the history from 1 to the current index - for i = 1, math.floor(index/2) do - filehistory[i], filehistory[index-i+1] = filehistory[index-i+1], filehistory[i] - end - - -- (2) if the file is in the history, remove it - for i = #filehistory, 1, -1 do - if isSameAs(filename, filehistory[i].filename) then - table.remove(filehistory, i) - end - end - - -- (3) add the file to the top and update the index - table.insert(filehistory, 1, {filename=filename}) - filehistory[0] = 1 - - -- (4) remove all entries that are no longer needed - while #filehistory>ide.config.filehistorylength do table.remove(filehistory) end - end - - local function remFileHistory(filename) - if not filename then return end - - local fn = wx.wxFileName(filename) - if fn:Normalize() then filename = fn:GetFullPath() end - - local index = filehistory[0] - - -- special case: removing the current file - if filehistory[index] and isSameAs(filename, filehistory[index].filename) then - -- (1) flip the history from 1 to the current index - for i = 1, math.floor(index/2) do - filehistory[i], filehistory[index-i+1] = filehistory[index-i+1], filehistory[i] - end - end - - -- (2) if the file is in the history, remove it - for i = #filehistory, 1, -1 do - if isSameAs(filename, filehistory[i].filename) then - table.remove(filehistory, i) - end - end - - -- (3) update index - filehistory[0] = 1 - end - - local updateRecentFiles -- need forward declaration because of recursive refs - - local function loadRecent(event) - local id = event:GetId() - local item = filehistorymenu:FindItem(id) - local filename = item:GetLabel() - local index = filehistory[0] - filehistory[0] = ( - (index > 1 and id == ID("file.recentfiles."..(index-1)) and index-1) or - (index < #filehistory) and id == ID("file.recentfiles."..(index+1)) and index+1 or - 1) - if not LoadFile(filename, nil, true) then - wx.wxMessageBox( - TR("File '%s' no longer exists."):format(filename), - GetIDEString("editormessage"), - wx.wxOK + wx.wxCENTRE, ide.frame) - remFileHistory(filename) - updateRecentFiles(filehistory) - end - end - - local items = 0 - updateRecentFiles = function (list) - -- protect against recent files menu not being present - if not ide:FindMenuItem(ID_RECENTFILES) then return end - - for i=1, #list do - local file = list[i].filename - local id = ID("file.recentfiles."..i) - local label = file..( - i == list[0]-1 and KSC(ID_RECENTFILESNEXT) or - i == list[0]+1 and KSC(ID_RECENTFILESPREV) or - "") - if i <= items then -- this is an existing item; update the label - filehistorymenu:FindItem(id):SetItemLabel(label) - else -- need to add an item - local item = wx.wxMenuItem(filehistorymenu, id, label, "") - filehistorymenu:Insert(i-1, item) - frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent) - end - end - for i=items, #list+1, -1 do -- delete the rest if the list got shorter - filehistorymenu:Delete(filehistorymenu:FindItemByPosition(i-1)) - end - items = #list -- update the number of items for the next refresh - - -- enable if there are any recent files - fileMenu:Enable(ID_RECENTFILES, #list > 0) - end - - -- public methods - function GetFileHistory() return filehistory end - function SetFileHistory(fh) - filehistory = fh - filehistory[0] = 1 - updateRecentFiles(filehistory) - end - function AddToFileHistory(filename) - addFileHistory(filename) - updateRecentFiles(filehistory) - end - - function FileRecentListUpdate(menu) - local list = filehistory - for i=#list, 1, -1 do - local id = ID("file.recentfiles."..i) - local label = list[i].filename - local item = wx.wxMenuItem(menu, id, label, "") - menu:Insert(0, item) - ide.frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent) - end - end -end - -frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, function() return NewFile() end) -frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile) -frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - local editor = ide.findReplace:CanSave(GetEditorWithFocus()) or GetEditor() - local doc = ide:GetDocument(editor) - SaveFile(editor, doc and doc:GetFilePath() or nil) - end) -frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI, - function (event) - local doc = ide:GetDocument(GetEditor()) - event:Enable(ide.findReplace:CanSave(GetEditorWithFocus()) and true - or doc and (doc:IsModified() or doc:IsNew()) or false) - end) - -frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - SaveFileAs(GetEditor()) - end) -frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(GetEditor() ~= nil) - end) - -frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - SaveAll() - end) -frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI, - function (event) - local atLeastOneModifiedDocument = false - for _, document in pairs(openDocuments) do - if document.isModified or not document.filePath then - atLeastOneModifiedDocument = true - break - end - end - event:Enable(atLeastOneModifiedDocument) - end) - -frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditorWithFocus() - local nb = ide:GetOutputNotebook() - local index = editor and nb:GetPageIndex(editor) - if index and ide.findReplace:IsPreview(editor) and index >= 0 then - nb:DeletePage(index) -- close preview tab - else - ClosePage() -- this will find the current editor tab - end - end) -frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(ide.findReplace:IsPreview(GetEditorWithFocus()) or GetEditor() ~= nil) - end) - -frame:Connect(ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - frame:Close() -- this will trigger wxEVT_CLOSE_WINDOW - end) - -frame:Connect(ID_RECENTPROJECTSCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) FileTreeProjectListClear() end) - -frame:Connect(ID_RECENTFILESCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - SetFileHistory({}) - local ed = ide:GetEditor() - if ed then AddToFileHistory(ide:GetDocument(ed):GetFilePath()) end - end) - -local recentprojects = 0 -frame:Connect(ID_RECENTPROJECTS, wx.wxEVT_UPDATE_UI, - function (event) - recentprojects = FileTreeProjectListUpdate(projecthistorymenu, recentprojects) - if not recentprojects then return end - local pos = 1 -- add shortcut for the previous project (if any) - if recentprojects > pos then - local item = projecthistorymenu:FindItemByPosition(pos) - item:SetItemLabel(item:GetItemLabelText()..KSC(ID_RECENTPROJECTSPREV)) - end - event:Enable(recentprojects > 0) - end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_help.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_help.lua deleted file mode 100644 index e2f3f2f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_help.lua +++ /dev/null @@ -1,118 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC ---------------------------------------------------------- - -local ide = ide --- --------------------------------------------------------------------------- --- Create the Help menu and attach the callback functions - -local frame = ide.frame -local menuBar = frame.menuBar -local mobdebug = require "mobdebug" - -local product = GetIDEString("help", "zerobranestudio") -local url = "http://zerobrane.com/r/"..product.."-" -local urls = { - [ID_HELPPROJECT] = "main", - [ID_HELPDOCUMENTATION] = "documentation", - [ID_HELPGETTINGSTARTED] = "gettingstarted", - [ID_HELPTUTORIALS] = "tutorials", - [ID_HELPFAQ] = "faq", - [ID_HELPCOMMUNITY] = "community", -} - -local helpMenu = wx.wxMenu{ - { ID_ABOUT, TR("&About")..KSC(ID_ABOUT), TR("About %s"):format(GetIDEString("editor")) }, - { ID_HELPPROJECT, TR("&Project Page")..KSC(ID_HELPPROJECT) }, - { ID_HELPDOCUMENTATION, TR("&Documentation")..KSC(ID_HELPDOCUMENTATION) }, - { ID_HELPGETTINGSTARTED, TR("&Getting Started Guide")..KSC(ID_HELPGETTINGSTARTED) }, - { ID_HELPTUTORIALS, TR("&Tutorials")..KSC(ID_HELPTUTORIALS) }, - { ID_HELPFAQ, TR("&Frequently Asked Questions")..KSC(ID_HELPFAQ) }, - { ID_HELPCOMMUNITY, TR("&Community")..KSC(ID_HELPCOMMUNITY) }, -} --- do not translate Help menu on Mac as it won't merge with "standard" menus -menuBar:Append(helpMenu, ide.osname == 'Macintosh' and "&Help" or TR("&Help")) - -local function displayAbout(event) - local logo = ide:GetAppName().."/"..GetIDEString("logo") - local logoimg = wx.wxFileName(logo):FileExists() and - ([[]]):format(logo) or "" - local page = ([[ - - - - %s -
- - - - - - - - - - - - - - -
- ZeroBrane Studio (%s; MobDebug %s)
- Copyright © 2011-2015 ZeroBrane LLC
- Paul Kulchenko
- Licensed under the MIT License. -
- Based on Estrela Editor
- Copyright © 2008-2011 Luxinia DevTeam
- Christoph Kubisch, Eike Decker
- Licensed under the MIT License. -
- Based on wxLua editor
- Copyright © 2002-2005 Lomtick Software
- J. Winwood, John Labenski
- Licensed under wxWindows Library License, v3. -
- Built with %s, %s -
-
- - ]]) - :format(logoimg, ide.VERSION, mobdebug._VERSION, ide:GetAppName(), - wx.wxVERSION_STRING, wxlua.wxLUA_VERSION_STRING) - - local dlg = wx.wxDialog(frame, wx.wxID_ANY, TR("About %s"):format(GetIDEString("editor"))) - - -- this is needed because wxLuaHtmlWindow only seems to take into account - -- the initial size, but not the one set with SetSize using - -- wxlua 2.8.12.2 and wxwidgets 2.9.5+. - local tmp = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxSize(450, 260)) - tmp:SetPage(page) - local w = tmp:GetInternalRepresentation():GetWidth() - local h = tmp:GetInternalRepresentation():GetHeight() - tmp:Destroy() - - local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(w, h), wx.wxHW_SCROLLBAR_NEVER) - - html:SetBorders(0) - html:SetPage(page) - - local line = wx.wxStaticLine(dlg, wx.wxID_ANY) - local button = wx.wxButton(dlg, wx.wxID_OK, "OK") - button:SetDefault() - - local topsizer = wx.wxBoxSizer(wx.wxVERTICAL) - topsizer:Add(html, 1, wx.wxEXPAND + wx.wxALL, 10) - topsizer:Add(line, 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10) - topsizer:Add(button, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10) - - dlg:SetSizerAndFit(topsizer) - dlg:ShowModal() - dlg:Destroy() -end - -frame:Connect(ID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, displayAbout) -for item, page in pairs(urls) do - frame:Connect(item, wx.wxEVT_COMMAND_MENU_SELECTED, - function() wx.wxLaunchDefaultBrowser(url..page, 0) end) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_project.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_project.lua deleted file mode 100644 index 22bf8f5..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_project.lua +++ /dev/null @@ -1,474 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local menuBar = frame.menuBar -local openDocuments = ide.openDocuments -local debugger = ide.debugger -local bottomnotebook = frame.bottomnotebook -local uimgr = frame.uimgr - ------------------------- --- Interpreters and Menu - -local debugTab = { - { ID_RUN, TR("&Run")..KSC(ID_RUN), TR("Execute the current project/file") }, - { ID_RUNNOW, TR("Run As Scratchpad")..KSC(ID_RUNNOW), TR("Execute the current project/file and keep updating the code to see immediate results"), wx.wxITEM_CHECK }, - { ID_COMPILE, TR("&Compile")..KSC(ID_COMPILE), TR("Compile the current file") }, - { ID_STARTDEBUG, TR("Start &Debugging")..KSC(ID_STARTDEBUG), TR("Start or continue debugging") }, - { ID_ATTACHDEBUG, TR("&Start Debugger Server")..KSC(ID_ATTACHDEBUG), TR("Allow external process to start debugging"), wx.wxITEM_CHECK }, - { }, - { ID_STOPDEBUG, TR("S&top Debugging")..KSC(ID_STOPDEBUG), TR("Stop the currently running process") }, - { ID_DETACHDEBUG, TR("Detach &Process")..KSC(ID_DETACHDEBUG), TR("Stop debugging and continue running the process") }, - { ID_STEP, TR("Step &Into")..KSC(ID_STEP), TR("Step into") }, - { ID_STEPOVER, TR("Step &Over")..KSC(ID_STEPOVER), TR("Step over") }, - { ID_STEPOUT, TR("Step O&ut")..KSC(ID_STEPOUT), TR("Step out of the current function") }, - { ID_RUNTO, TR("Run To Cursor")..KSC(ID_RUNTO), TR("Run to cursor") }, - { ID_TRACE, TR("Tr&ace")..KSC(ID_TRACE), TR("Trace execution showing each executed line") }, - { ID_BREAK, TR("&Break")..KSC(ID_BREAK), TR("Break execution at the next executed line of code") }, - { }, - { ID_BREAKPOINT, TR("Breakpoint")..KSC(ID_BREAKPOINT) }, - { }, - { ID_CLEAROUTPUT, TR("C&lear Output Window")..KSC(ID_CLEAROUTPUT), TR("Clear the output window before compiling or debugging"), wx.wxITEM_CHECK }, - { ID_COMMANDLINEPARAMETERS, TR("Command Line Parameters...")..KSC(ID_COMMANDLINEPARAMETERS), TR("Provide command line parameters") }, -} - -local targetDirMenu = wx.wxMenu{ - {ID_PROJECTDIRCHOOSE, TR("Choose...")..KSC(ID_PROJECTDIRCHOOSE), TR("Choose a project directory")}, - {ID_PROJECTDIRFROMFILE, TR("Set From Current File")..KSC(ID_PROJECTDIRFROMFILE), TR("Set project directory from current file")}, -} -local targetMenu = wx.wxMenu({}) -local debugMenu = wx.wxMenu(debugTab) -local debugMenuRun = { - start=TR("Start &Debugging")..KSC(ID_STARTDEBUG), continue=TR("Co&ntinue")..KSC(ID_STARTDEBUG)} -local debugMenuStop = { - debugging=TR("S&top Debugging")..KSC(ID_STOPDEBUG), process=TR("S&top Process")..KSC(ID_STOPDEBUG)} -debugMenu:Append(ID_PROJECTDIR, TR("Project Directory"), targetDirMenu, TR("Set the project directory to be used")) -debugMenu:Append(ID_INTERPRETER, TR("Lua &Interpreter"), targetMenu, TR("Set the interpreter to be used")) -menuBar:Append(debugMenu, TR("&Project")) - -ide:AttachMenu(ID_BREAKPOINT, wx.wxMenu { - { ID_BREAKPOINTTOGGLE, TR("Toggle Breakpoint")..KSC(ID_BREAKPOINTTOGGLE) }, - { ID_BREAKPOINTNEXT, TR("Go To Next Breakpoint")..KSC(ID_BREAKPOINTNEXT) }, - { ID_BREAKPOINTPREV, TR("Go To Previous Breakpoint")..KSC(ID_BREAKPOINTPREV) }, -}) - -local interpreters -local function selectInterpreter(id) - for id in pairs(interpreters) do - menuBar:Check(id, false) - menuBar:Enable(id, true) - end - menuBar:Check(id, true) - menuBar:Enable(id, false) - - local changed = ide.interpreter ~= interpreters[id] - if ide.interpreter and changed then - PackageEventHandle("onInterpreterClose", ide.interpreter) - end - if interpreters[id] and changed then - PackageEventHandle("onInterpreterLoad", interpreters[id]) - end - - ide.interpreter = interpreters[id] - - DebuggerShutdown() - - ide:SetStatus(ide.interpreter.name or "", 4) - if changed then ReloadLuaAPI() end -end - -function ProjectSetInterpreter(name) - local id = IDget("debug.interpreter."..name) - if id and interpreters[id] then - selectInterpreter(id) - else - DisplayOutputLn(("Can't find interpreter '%s'; using the default interpreter instead.") - :format(name)) - local id = ( - -- interpreter is set and is (still) on the list of known interpreters - IDget("debug.interpreter."..(ide.config.interpreter or ide.config.default.interpreter)) or - -- otherwise use default interpreter - ID("debug.interpreter."..ide.config.default.interpreter) - ) - selectInterpreter(id) - end -end - -local function evSelectInterpreter(event) - selectInterpreter(event:GetId()) -end - -function ProjectUpdateInterpreters() - assert(ide.interpreters, "no interpreters defined") - - -- delete all existing items (if any) - local items = targetMenu:GetMenuItemCount() - for i = items, 1, -1 do - targetMenu:Delete(targetMenu:FindItemByPosition(i-1)) - end - - local names = {} - for file in pairs(ide.interpreters) do table.insert(names, file) end - table.sort(names) - - interpreters = {} - for _, file in ipairs(names) do - local inter = ide.interpreters[file] - local id = ID("debug.interpreter."..file) - inter.fname = file - interpreters[id] = inter - targetMenu:Append( - wx.wxMenuItem(targetMenu, id, inter.name, inter.description, wx.wxITEM_CHECK)) - frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, evSelectInterpreter) - end - - local id = ( - -- interpreter is set and is (still) on the list of known interpreters - IDget("debug.interpreter." - ..(ide.interpreter and ide.interpreters[ide.interpreter.fname] and ide.interpreter.fname - or ide.config.interpreter or ide.config.default.interpreter)) or - -- otherwise use default interpreter - ID("debug.interpreter."..ide.config.default.interpreter) - ) - selectInterpreter(id) -end - ------------------------------ --- Project directory handling - -function ProjectUpdateProjectDir(projdir,skiptree) - -- strip trailing spaces as this may create issues with "path/ " on Windows - projdir = projdir:gsub("%s+$","") - local dir = wx.wxFileName.DirName(FixDir(projdir)) - dir:Normalize() -- turn into absolute path if needed - if not wx.wxDirExists(dir:GetFullPath()) then return end - - projdir = dir:GetPath(wx.wxPATH_GET_VOLUME) -- no trailing slash - - ide.config.path.projectdir = projdir ~= "" and projdir or nil - ide:SetStatus(projdir) - frame:SetTitle(ExpandPlaceholders(ide.config.format.apptitle)) - if (not skiptree) then ide.filetree:updateProjectDir(projdir) end - return true -end - -local function projChoose(event) - local editor = GetEditor() - local fn = wx.wxFileName( - editor and openDocuments[editor:GetId()].filePath or "") - fn:Normalize() -- want absolute path for dialog - - local projectdir = ide:GetProject() - local filePicker = wx.wxDirDialog(frame, TR("Choose a project directory"), - projectdir ~= "" and projectdir or wx.wxGetCwd(), wx.wxDIRP_DIR_MUST_EXIST) - if filePicker:ShowModal(true) == wx.wxID_OK then - return ProjectUpdateProjectDir(filePicker:GetPath()) - end - return false -end - -frame:Connect(ID_PROJECTDIRCHOOSE, wx.wxEVT_COMMAND_MENU_SELECTED, projChoose) - -local function projFromFile(event) - local editor = GetEditor() - if not editor then return end - local id = editor:GetId() - local filepath = openDocuments[id].filePath - if not filepath then return end - local fn = wx.wxFileName(filepath) - fn:Normalize() -- want absolute path for dialog - - if ide.interpreter then - ProjectUpdateProjectDir(ide.interpreter:fprojdir(fn)) end -end -frame:Connect(ID_PROJECTDIRFROMFILE, wx.wxEVT_COMMAND_MENU_SELECTED, projFromFile) -frame:Connect(ID_PROJECTDIRFROMFILE, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable(editor ~= nil and ide:GetDocument(editor):GetFilePath() ~= nil) - end) - ----------------------- --- Interpreter Running - -local function getNameToRun(skipcheck) - local editor = GetEditor() - if not editor then return end - - -- test compile it before we run it, if successful then ask to save - -- only compile if lua api - if editor.spec.apitype and - editor.spec.apitype == "lua" and - (not skipcheck) and - (not ide.interpreter.skipcompile) and - (not CompileProgram(editor, { reportstats = false })) then - return - end - - local doc = ide:GetDocument(editor) - local name = ide:GetProjectStartFile() or doc:GetFilePath() - if not name then doc:SetModified(true) end - if not SaveIfModified(editor) then return end - if ide.config.editor.saveallonrun then SaveAll(true) end - - return wx.wxFileName(name or doc:GetFilePath()) -end - -function ActivateOutput() - if not ide.config.activateoutput then return end - -- show output/errorlog pane - if not uimgr:GetPane(bottomnotebook):IsShown() then - uimgr:GetPane(bottomnotebook):Show(true) - uimgr:Update() - end - -- activate output/errorlog window - local index = bottomnotebook:GetPageIndex(bottomnotebook.errorlog) - if bottomnotebook:GetSelection() ~= index then - bottomnotebook:SetSelection(index) - end -end - -local function runInterpreter(wfilename, withdebugger) - ClearOutput() - ActivateOutput() - - ClearAllCurrentLineMarkers() - if not wfilename then return end - debugger.pid = ide.interpreter:frun(wfilename, withdebugger) - if debugger.pid then OutputEnableInput() end - return debugger.pid -end - -function ProjectRun(skipcheck) - local fname = getNameToRun(skipcheck) - if not fname then return end - return runInterpreter(fname) -end - -local debuggers = { - debug = "require('mobdebug').loop('%s',%d)", - scratchpad = "require('mobdebug').scratchpad('%s',%d)" -} - -function ProjectDebug(skipcheck, debtype) - if (debugger.server ~= nil) then - if (debugger.scratchpad and debugger.scratchpad.paused) then - debugger.scratchpad.paused = nil - debugger.scratchpad.updated = true - ShellSupportRemote(nil) -- disable remote while Scratchpad running - elseif (not debugger.running) then - debugger.run() - end - else - local debcall = (debuggers[debtype or "debug"]): - format(ide.debugger.hostname, ide.debugger.portnumber) - local fname = getNameToRun(skipcheck) - if not fname then return end - return runInterpreter(fname, debcall) -- this may be pid or nil - end - return true -end - ------------------------ --- Actions - -local BREAKPOINT_MARKER = StylesGetMarker("breakpoint") - -frame:Connect(ID_BREAKPOINTTOGGLE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() GetEditor():BreakpointToggle() end) -frame:Connect(ID_BREAKPOINTTOGGLE, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditorWithFocus(GetEditor()) - event:Enable((ide.interpreter) and (ide.interpreter.hasdebugger) and (editor ~= nil) - and (not debugger.scratchpad)) - end) - -frame:Connect(ID_BREAKPOINTNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local BPNSC = KSC(ID_BREAKPOINTNEXT):gsub("\t","") - if not GetEditor():MarkerGotoNext(BREAKPOINT_MARKER) and BPNSC == "F9" then - local osx = ide.osname == "Macintosh" - DisplayOutputLn(("You used '%s' shortcut that has been changed from toggling a breakpoint to navigating to the next breakpoint in the document.") - :format(BPNSC)) - DisplayOutputLn(("To toggle a breakpoint, use '%s' or click in the editor margin.") - :format(KSC(ID_BREAKPOINTTOGGLE):gsub("\t",""):gsub("Ctrl", osx and "Cmd" or "Ctrl"))) - end - end) -frame:Connect(ID_BREAKPOINTPREV, wx.wxEVT_COMMAND_MENU_SELECTED, - function() GetEditor():MarkerGotoPrev(BREAKPOINT_MARKER) end) - -frame:Connect(ID_BREAKPOINTNEXT, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(GetEditor() ~= nil) end) -frame:Connect(ID_BREAKPOINTPREV, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(GetEditor() ~= nil) end) - -frame:Connect(ID_COMPILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - ActivateOutput() - CompileProgram(GetEditor(), { - keepoutput = ide:GetLaunchedProcess() ~= nil or ide:GetDebugger():IsConnected() - }) - end) -frame:Connect(ID_COMPILE, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(GetEditor() ~= nil) end) - -frame:Connect(ID_RUN, wx.wxEVT_COMMAND_MENU_SELECTED, function () ProjectRun() end) -frame:Connect(ID_RUN, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server == nil and debugger.pid == nil) and (editor ~= nil)) - end) - -frame:Connect(ID_RUNNOW, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - if debugger.scratchpad then - DebuggerScratchpadOff() - else - DebuggerScratchpadOn(GetEditor()) - end - end) -frame:Connect(ID_RUNNOW, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - -- allow scratchpad if there is no server or (there is a server and it is - -- allowed to turn it into a scratchpad) and we are not debugging anything - event:Enable((ide.interpreter) and (ide.interpreter.hasdebugger) and - (ide.interpreter.scratchextloop ~= nil) and -- nil == no scratchpad support - (editor ~= nil) and ((debugger.server == nil or debugger.scratchable) - and debugger.pid == nil or debugger.scratchpad ~= nil)) - local isscratchpad = debugger.scratchpad ~= nil - menuBar:Check(ID_RUNNOW, isscratchpad) - local tool = ide:GetToolBar():FindTool(ID_RUNNOW) - if tool and tool:IsSticky() ~= isscratchpad then - tool:SetSticky(isscratchpad) - ide:GetToolBar():Refresh() - end - end) - -frame:Connect(ID_ATTACHDEBUG, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - if event:IsChecked() then - if (ide.interpreter.fattachdebug) then ide.interpreter:fattachdebug() end - else - debugger.listen(false) -- stop listening - end - end) -frame:Connect(ID_ATTACHDEBUG, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(ide.interpreter and ide.interpreter.fattachdebug and true or false) - ide.frame.menuBar:Check(event:GetId(), debugger.listening and true or false) - end) - -frame:Connect(ID_STARTDEBUG, wx.wxEVT_COMMAND_MENU_SELECTED, function () ProjectDebug() end) -frame:Connect(ID_STARTDEBUG, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((ide.interpreter) and (ide.interpreter.hasdebugger) and - ((debugger.server == nil and debugger.pid == nil and editor ~= nil) or - (debugger.server ~= nil and not debugger.running)) and - (not debugger.scratchpad or debugger.scratchpad.paused)) - local label = (debugger.server ~= nil) - and debugMenuRun.continue or debugMenuRun.start - if debugMenu:GetLabel(ID_STARTDEBUG) ~= label then - debugMenu:SetLabel(ID_STARTDEBUG, label) - end - end) - -frame:Connect(ID_STOPDEBUG, wx.wxEVT_COMMAND_MENU_SELECTED, - function () DebuggerShutdown() end) -frame:Connect(ID_STOPDEBUG, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(debugger.server ~= nil or debugger.pid ~= nil) - local label = (debugger.server == nil and debugger.pid ~= nil) - and debugMenuStop.process or debugMenuStop.debugging - if debugMenu:GetLabel(ID_STOPDEBUG) ~= label then - debugMenu:SetLabel(ID_STOPDEBUG, label) - end - end) - -frame:Connect(ID_DETACHDEBUG, wx.wxEVT_COMMAND_MENU_SELECTED, - function () debugger.detach() end) -frame:Connect(ID_DETACHDEBUG, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable((debugger.server ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_RUNTO, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - local editor = GetEditor() - debugger.runto(editor, editor:GetCurrentLine()) - end) -frame:Connect(ID_RUNTO, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server ~= nil) and (not debugger.running) - and (editor ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_STEP, wx.wxEVT_COMMAND_MENU_SELECTED, - function () debugger.step() end) -frame:Connect(ID_STEP, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server ~= nil) and (not debugger.running) - and (editor ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_STEPOVER, wx.wxEVT_COMMAND_MENU_SELECTED, - function () debugger.over() end) -frame:Connect(ID_STEPOVER, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server ~= nil) and (not debugger.running) - and (editor ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_STEPOUT, wx.wxEVT_COMMAND_MENU_SELECTED, - function () debugger.out() end) -frame:Connect(ID_STEPOUT, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server ~= nil) and (not debugger.running) - and (editor ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_TRACE, wx.wxEVT_COMMAND_MENU_SELECTED, - function () debugger.trace() end) -frame:Connect(ID_TRACE, wx.wxEVT_UPDATE_UI, - function (event) - local editor = GetEditor() - event:Enable((debugger.server ~= nil) and (not debugger.running) - and (editor ~= nil) and (not debugger.scratchpad)) - end) - -frame:Connect(ID_BREAK, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - if debugger.server then - debugger.breaknow() - if debugger.scratchpad then - debugger.scratchpad.paused = true - ShellSupportRemote(debugger.shell) - end - end - end) -frame:Connect(ID_BREAK, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(debugger.server ~= nil - and (debugger.running - or (debugger.scratchpad and not debugger.scratchpad.paused))) - end) - -frame:Connect(ID_COMMANDLINEPARAMETERS, wx.wxEVT_COMMAND_MENU_SELECTED, - function () - local params = wx.wxGetTextFromUser(TR("Enter command line parameters (use Cancel to clear)"), - TR("Command line parameters"), ide.config.arg.any or "") - ide.config.arg.any = params and #params > 0 and params or nil - end) -frame:Connect(ID_COMMANDLINEPARAMETERS, wx.wxEVT_UPDATE_UI, - function (event) - event:Enable(ide.interpreter and ide.interpreter.takeparameters and true or false) - end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_search.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_search.lua deleted file mode 100644 index 8fcad40..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_search.lua +++ /dev/null @@ -1,420 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local q = EscapeMagic -local unpack = table.unpack or unpack - -local frame = ide.frame -local menuBar = frame.menuBar -local findReplace = ide.findReplace - -local findMenu = wx.wxMenu{ - { ID_FIND, TR("&Find")..KSC(ID_FIND), TR("Find text") }, - { ID_FINDNEXT, TR("Find &Next")..KSC(ID_FINDNEXT), TR("Find the next text occurrence") }, - { ID_FINDPREV, TR("Find &Previous")..KSC(ID_FINDPREV), TR("Find the earlier text occurence") }, - { ID_FINDSELECTNEXT, TR("Select And Find Next")..KSC(ID_FINDSELECTNEXT), TR("Select the word under cursor and find its next occurrence") }, - { ID_FINDSELECTPREV, TR("Select And Find Previous")..KSC(ID_FINDSELECTPREV), TR("Select the word under cursor and find its previous occurrence") }, - { ID_REPLACE, TR("&Replace")..KSC(ID_REPLACE), TR("Find and replace text") }, - { }, - { ID_FINDINFILES, TR("Find &In Files")..KSC(ID_FINDINFILES), TR("Find text in files") }, - { ID_REPLACEINFILES, TR("Re&place In Files")..KSC(ID_REPLACEINFILES), TR("Find and replace text in files") }, - { }, -} -findMenu:Append(ID_NAVIGATE, TR("Navigate"), wx.wxMenu { - { ID_NAVIGATETOFILE, TR("Go To File...")..KSC(ID_NAVIGATETOFILE), TR("Go to file") }, - { ID_NAVIGATETOLINE, TR("Go To Line...")..KSC(ID_NAVIGATETOLINE), TR("Go to line") }, - { ID_NAVIGATETOSYMBOL, TR("Go To Symbol...")..KSC(ID_NAVIGATETOSYMBOL), TR("Go to symbol") }, - { ID_NAVIGATETOMETHOD, TR("Insert Library Function...")..KSC(ID_NAVIGATETOMETHOD), TR("Find and insert library function") }, -}) - -menuBar:Append(findMenu, TR("&Search")) - -local function onUpdateUISearchMenu(event) event:Enable(GetEditor() ~= nil) end - -frame:Connect(ID_FIND, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - findReplace:Show(false) - end) -frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - -frame:Connect(ID_REPLACE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - findReplace:Show(true) - end) -frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - -frame:Connect(ID_FINDINFILES, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - findReplace:Show(false,true) - end) -frame:Connect(ID_REPLACEINFILES, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - findReplace:Show(true,true) - end) - -frame:Connect(ID_FINDNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - if editor and ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then - local selection = editor:GetMainSelection() + 1 - if selection >= editor:GetSelections() then selection = 0 end - editor:SetMainSelection(selection) - editor:ShowPosEnforcePolicy(editor:GetCurrentPos()) - else - if findReplace:SetFind(findReplace:GetFind() or findReplace:GetSelection()) then - findReplace:Find() - else - findReplace:Show(false) - end - end - end) -frame:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - -frame:Connect(ID_FINDPREV, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - if editor and ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then - local selection = editor:GetMainSelection() - 1 - if selection < 0 then selection = editor:GetSelections() - 1 end - editor:SetMainSelection(selection) - editor:ShowPosEnforcePolicy(editor:GetCurrentPos()) - else - if findReplace:SetFind(findReplace:GetFind() or findReplace:GetSelection()) then - findReplace:Find(true) -- search up - else - findReplace:Show(false) - end - end - end) -frame:Connect(ID_FINDPREV, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - --- Select and Find behaves like Find if there is a current selection; --- if not, it selects a word under cursor (if any) and does find. - -frame:Connect(ID_FINDSELECTNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - if findReplace:SetFind(findReplace:GetSelection() or findReplace:GetWordAtCaret()) then - findReplace:Find() - end - end) -frame:Connect(ID_FINDSELECTNEXT, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - -frame:Connect(ID_FINDSELECTPREV, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - if findReplace:SetFind(findReplace:GetSelection() or findReplace:GetWordAtCaret()) then - findReplace:Find(true) - end - end) -frame:Connect(ID_FINDSELECTPREV, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu) - -local markername = "commandbar.background" -local mac = ide.osname == 'Macintosh' -local win = ide.osname == 'Windows' -local special = {SYMBOL = '@', LINE = ':', METHOD = ';'} -local tabsep = "\0" -local function name2index(name) - local p = name:find(tabsep) - return p and tonumber(name:sub(p + #tabsep)) or nil -end -local function navigateTo(default, selected) - local styles = ide.config.styles - local marker = ide:AddMarker(markername, - wxstc.wxSTC_MARK_BACKGROUND, styles.text.fg, styles.caretlinebg.bg) - - local nb = ide:GetEditorNotebook() - local selection = nb:GetSelection() - local maxitems = ide.config.commandbar.maxitems - local files, preview, origline, functions, methods - - local function markLine(ed, toline) - ed:MarkerDefine(ide:GetMarker(markername)) - ed:MarkerDeleteAll(marker) - ed:MarkerAdd(toline-1, marker) - -- store the original line if not stored yet - origline = origline or (ed:GetCurrentLine()+1) - ed:EnsureVisibleEnforcePolicy(toline-1) - end - - CommandBarShow({ - defaultText = default or "", - selectedText = selected or "", - onDone = function(t, enter, text) - if not mac then nb:Freeze() end - - -- delete all current line markers if any; restore line position - local ed = ide:GetEditor() - if ed and origline then - ed:MarkerDeleteAll(marker) - -- only restore original line if Escape was used (enter == false) - if enter == false then ed:EnsureVisibleEnforcePolicy(origline-1) end - end - - local pindex = preview and nb:GetPageIndex(preview) - if enter then - local fline, sline, tabindex = unpack(t or {}) - - -- jump to symbol; tabindex has the position of the symbol - if text and text:find(special.SYMBOL) then - if sline and tabindex then - local index = name2index(sline) - local editor = index and nb:GetPage(index):DynamicCast("wxStyledTextCtrl") - if not editor then - local doc = ide:FindDocument(sline) - -- reload the file (including the preview to refresh its symbols in the outline) - editor = LoadFile(sline, (not doc or doc:GetTabIndex() == pindex) and preview or nil) - end - if editor then - if pindex and pindex ~= ide:GetDocument(editor):GetTabIndex() then ClosePage(pindex) end - editor:SetFocus() -- in case the focus is on some other panel - editor:GotoPos(tabindex-1) - editor:EnsureVisibleEnforcePolicy(editor:LineFromPosition(tabindex-1)) - end - end - -- insert selected method - elseif text and text:find('^%s*'..special.METHOD) then - if ed then -- clean up text and insert at the current location - local method = sline - local isfunc = methods.desc[method][1]:find(q(method).."%s*%(") - local text = method .. (isfunc and "()" or "") - local pos = ed:GetCurrentPos() - ed:InsertTextDyn(pos, text) - ed:EnsureVisibleEnforcePolicy(ed:LineFromPosition(pos)) - ed:GotoPos(pos + #method + (isfunc and 1 or 0)) - if isfunc then -- show the tooltip - ide.frame:AddPendingEvent(wx.wxCommandEvent( - wx.wxEVT_COMMAND_MENU_SELECTED, ID_SHOWTOOLTIP)) - end - end - -- set line position in the (current) editor if requested - elseif text and text:find(special.LINE..'(%d+)%s*$') then - local toline = tonumber(text:match(special.LINE..'(%d+)')) - if toline and ed then - ed:GotoLine(toline-1) - ed:EnsureVisibleEnforcePolicy(toline-1) - ed:SetFocus() -- in case the focus is on some other panel - end - elseif tabindex then -- switch to existing tab - SetEditorSelection(tabindex) - if pindex and pindex ~= tabindex then ClosePage(pindex) end - -- load a new file (into preview if set) - elseif sline or text then - -- 1. use "text" if Ctrl/Cmd-Enter is used - -- 2. otherwise use currently selected file - -- 3. otherwise use "text" - local file = (wx.wxGetKeyState(wx.WXK_CONTROL) and text) or sline or text - local fullPath = MergeFullPath(ide:GetProject(), file) - local doc = ide:FindDocument(fullPath) - -- if the document is already opened (not in the preview) - -- or can't be opened as a file or folder, then close the preview - if doc and doc.index ~= pindex - or not LoadFile(fullPath, preview or nil) and not ProjectUpdateProjectDir(fullPath) then - if pindex then ClosePage(pindex) end - end - end - elseif enter == nil then -- changed focus - -- do nothing; keep everything as is - else - -- close preview - if pindex then ClosePage(pindex) end - -- restore original selection if canceled - if nb:GetSelection() ~= selection then nb:SetSelection(selection) end - end - preview = nil - if not mac then nb:Thaw() end - end, - onUpdate = function(text) - local lines = {} - local projdir = ide:GetProject() - - -- delete all current line markers if any - -- restore the original position if search text is updated - local ed = ide:GetEditor() - if ed and origline then ed:MarkerDeleteAll(marker) end - - -- reset cached functions if no symbol search - if text and not text:find(special.SYMBOL) then - functions = nil - if ed and origline then ed:EnsureVisibleEnforcePolicy(origline-1) end - end - -- reset cached methods if no method search - if text and not text:find(special.METHOD) then methods = nil end - - if text and text:find(special.SYMBOL) then - local file, symbol = text:match('^(.*)'..special.SYMBOL..'(.*)') - if not functions then - local nums, paths = {}, {} - functions = {pos = {}, src = {}} - - local function populateSymbols(path, symbols) - for _, func in ipairs(symbols) do - table.insert(functions, func.name) - nums[func.name] = (nums[func.name] or 0) + 1 - local num = nums[func.name] - functions.src[func.name..num] = path - functions.pos[func.name..num] = func.pos - end - end - - local currentonly = #file > 0 and ed - local outline = ide:GetOutline() - for _, doc in pairs(currentonly and {ide:GetDocument(ed)} or ide:GetDocuments()) do - local path, editor = doc:GetFilePath(), doc:GetEditor() - if path then paths[path] = true end - populateSymbols(path or doc:GetFileName()..tabsep..doc:GetTabIndex(), outline:GetEditorSymbols(editor)) - end - - -- now add all other files in the project - if not currentonly and ide.config.commandbar.showallsymbols then - local n = 0 - outline:RefreshSymbols(projdir, function(path) - local symbols = outline:GetFileSymbols(path) - if not paths[path] and symbols then populateSymbols(path, symbols) end - if not symbols then n = n + 1 end - end) - if n > 0 then ide:SetStatusFor(TR("Queued %d files to index."):format(n)) end - end - end - local nums = {} - if #symbol > 0 then - local topscore - for _, item in ipairs(CommandBarScoreItems(functions, symbol, maxitems)) do - local func, score = unpack(item) - topscore = topscore or score - nums[func] = (nums[func] or 0) + 1 - local num = nums[func] - if score > topscore / 4 and score > 1 then - table.insert(lines, {("%2d %s"):format(score, func), - functions.src[func..num], functions.pos[func..num]}) - end - end - else - for n, name in ipairs(functions) do - if n > maxitems then break end - nums[name] = (nums[name] or 0) + 1 - local num = nums[name] - lines[n] = {name, functions.src[name..num], functions.pos[name..num]} - end - end - elseif ed and text and text:find('^%s*'..special.METHOD) then - if not methods then - methods = {desc = {}} - local num = 1 - if ed.api and ed.api.tip and ed.api.tip.shortfinfoclass then - for libname, lib in pairs(ed.api.tip.shortfinfoclass) do - for method, val in pairs(lib) do - local signature, desc = val:match('(.-)\n(.*)') - local m = libname..'.'..method - desc = desc and desc:gsub("\n", " ") or val - methods[num] = m - methods.desc[m] = {signature or (libname..'.'..method), desc} - num = num + 1 - end - end - end - end - local method = text:match(special.METHOD..'(.*)') - if #method > 0 then - local topscore - for _, item in ipairs(CommandBarScoreItems(methods, method, maxitems)) do - local method, score = unpack(item) - topscore = topscore or score - if score > topscore / 4 and score > 1 then - table.insert(lines, { score, method }) - end - end - end - elseif text and text:find(special.LINE..'(%d*)%s*$') then - local toline = tonumber(text:match(special.LINE..'(%d+)')) - if toline and ed then markLine(ed, toline) end - elseif text and #text > 0 and projdir and #projdir > 0 then - -- populate the list of files - files = files or FileSysGetRecursive(projdir, true, "*", - {sort = false, path = false, folder = false, skipbinary = true}) - local topscore - for _, item in ipairs(CommandBarScoreItems(files, text, maxitems)) do - local file, score = unpack(item) - topscore = topscore or score - if score > topscore / 4 and score > 1 then - table.insert(lines, { - ("%2d %s"):format(score, wx.wxFileName(file):GetFullName()), - file, - }) - end - end - else - for _, doc in pairs(ide:GetDocuments()) do - lines[doc:GetTabIndex()+1] = {doc:GetFileName(), doc:GetFilePath(), doc:GetTabIndex()} - end - end - return lines - end, - onItem = function(t) - if methods then - local score, method = unpack(t) - return ("%2d %s"):format(score, methods.desc[method][1]), methods.desc[method][2] - else - return unpack(t) - end - end, - onSelection = function(t, text) - local _, file, tabindex = unpack(t) - local pos - if text and text:find(special.SYMBOL) then - pos, tabindex = tabindex, name2index(file) - elseif text and text:find(special.METHOD) then - return - end - - if file then file = MergeFullPath(ide:GetProject(), file) end - -- disabling event handlers for the notebook and the editor - -- to minimize changes in the UI when editors are switched - -- or files in the preview are updated. - nb:SetEvtHandlerEnabled(false) - local doc = file and ide:FindDocument(file) - if doc and not tabindex then tabindex = doc:GetTabIndex() end - if tabindex then - local ed = nb:GetPage(tabindex) - ed:SetEvtHandlerEnabled(false) - if nb:GetSelection() ~= tabindex then nb:SetSelection(tabindex) end - ed:SetEvtHandlerEnabled(true) - elseif file then - -- skip binary files with unknown extensions - if #ide:GetKnownExtensions(GetFileExt(file)) > 0 - or not IsBinary(FileRead(file, 2048)) then - preview = preview or NewFile() - preview:SetEvtHandlerEnabled(false) - LoadFile(file, preview, true, true) - preview:SetFocus() - -- force refresh since the panel covers the editor on OSX/Linux - -- this fixes the preview window not always redrawn on Linux - if not win then preview:Update() preview:Refresh() end - preview:SetEvtHandlerEnabled(true) - elseif preview then - ClosePage(nb:GetPageIndex(preview)) - preview = nil - end - end - nb:SetEvtHandlerEnabled(true) - - if text and text:find(special.SYMBOL) then - local ed = ide:GetEditor() - if ed then markLine(ed, ed:LineFromPosition(pos-1)+1) end - end - end, - }) -end - -frame:Connect(ID_NAVIGATETOFILE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() navigateTo("") end) -frame:Connect(ID_NAVIGATETOLINE, wx.wxEVT_COMMAND_MENU_SELECTED, - function() navigateTo(special.LINE) end) -frame:Connect(ID_NAVIGATETOMETHOD, wx.wxEVT_COMMAND_MENU_SELECTED, - function() navigateTo(special.METHOD) end) -frame:Connect(ID_NAVIGATETOSYMBOL, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - local ed = GetEditor() - navigateTo(special.SYMBOL, ed and ed:ValueFromPosition(ed:GetCurrentPos())) - end) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_tools.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_tools.lua deleted file mode 100644 index 885556c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_tools.lua +++ /dev/null @@ -1,111 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local menuBar = frame.menuBar -local unpack = table.unpack or unpack - ---[=[ --- tool definition --- main entries are optional -tool = { - fnmenu = function(frame,menubar), - -- can be used for init - -- and custom menu - exec = { - -- quick exec action - name = "", - description = "", - fn = function(filename, projectdir), - } -} - -]=] - -local toolArgs = {} -local cnt = 1 - -local function name2id(name) return ID("tools.exec."..name) end - -do - local maxcnt = 10 - - local tools = {} - for name,tool in pairs(ide.tools) do - if (tool.exec and tool.exec.name) then - tool.fname = name - table.insert(tools,tool) - end - end - - table.sort(tools,function(a,b) return a.exec.name < b.exec.name end) - - -- todo config specifc ignore/priority list - for _, tool in ipairs(tools) do - local exec = tool.exec - if (exec and cnt < maxcnt and exec.name and exec.fn and exec.description) then - local id = name2id(tool.fname) - table.insert(toolArgs,{id, TR(exec.name) .. KSC(id), exec.description}) - -- flag it - tool._execid = id - cnt = cnt + 1 - end - end -end - -local function addHandler(menu, id, command, updateui) - menu:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local editor = GetEditor() - if (not editor) then return end - - command(ide:GetDocument(editor):GetFilePath(), ide:GetProject()) - - return true - end) - menu:Connect(id, wx.wxEVT_UPDATE_UI, - updateui or function(event) event:Enable(GetEditor() ~= nil) end) -end - -if (cnt > 1) then - - -- Build Menu - local toolMenu = wx.wxMenu{ - unpack(toolArgs) - } - menuBar:Append(toolMenu, "&Tools") - - -- connect auto execs - for _, tool in pairs(ide.tools) do - if tool._execid then addHandler(toolMenu, tool._execid, tool.exec.fn) end - end -end - --- Generate Custom Menus/Init -for _, tool in pairs(ide.tools) do - if tool.fninit then tool.fninit(frame, menuBar) end -end - -function ToolsAddTool(name, command, updateui) - local toolMenu = ide:FindTopMenu('&Tools') - if not toolMenu then - local helpMenu, helpindex = ide:FindTopMenu('&Help') - if not helpMenu then helpindex = ide:GetMenuBar():GetMenuCount() end - - toolMenu = wx.wxMenu{} - menuBar:Insert(helpindex, toolMenu, "&Tools") - end - local id = name2id(name) - toolMenu:Append(id, name) - addHandler(toolMenu, id, command, updateui) -end - -function ToolsRemoveTool(name) - ide:RemoveMenuItem(name2id(name)) - local toolMenu, toolindex = ide:FindTopMenu('&Tools') - if toolMenu and toolMenu:GetMenuItemCount() == 0 then - ide:GetMenuBar():Remove(toolindex) - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_view.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_view.lua deleted file mode 100644 index 71f6648..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/menu_view.lua +++ /dev/null @@ -1,113 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local menuBar = frame.menuBar -local uimgr = frame.uimgr - -local viewMenu = wx.wxMenu { - { ID_VIEWFILETREE, TR("Project/&FileTree Window")..KSC(ID_VIEWFILETREE), TR("View the project/filetree window"), wx.wxITEM_CHECK }, - { ID_VIEWOUTPUT, TR("&Output/Console Window")..KSC(ID_VIEWOUTPUT), TR("View the output/console window"), wx.wxITEM_CHECK }, - { ID_VIEWWATCHWINDOW, TR("&Watch Window")..KSC(ID_VIEWWATCHWINDOW), TR("View the watch window"), wx.wxITEM_CHECK }, - { ID_VIEWCALLSTACK, TR("&Stack Window")..KSC(ID_VIEWCALLSTACK), TR("View the stack window"), wx.wxITEM_CHECK }, - { ID_VIEWOUTLINE, TR("Outline Window")..KSC(ID_VIEWOUTLINE), TR("View the outline window"), wx.wxITEM_CHECK }, - { ID_VIEWMARKERS, TR("Markers Window")..KSC(ID_VIEWMARKERS), TR("View the markers window"), wx.wxITEM_CHECK }, - { }, - { ID_VIEWTOOLBAR, TR("&Tool Bar")..KSC(ID_VIEWTOOLBAR), TR("Show/Hide the toolbar"), wx.wxITEM_CHECK }, - { ID_VIEWSTATUSBAR, TR("&Status Bar")..KSC(ID_VIEWSTATUSBAR), TR("Show/Hide the status bar"), wx.wxITEM_CHECK }, - { }, - { ID_VIEWDEFAULTLAYOUT, TR("&Default Layout")..KSC(ID_VIEWDEFAULTLAYOUT), TR("Reset to default layout") }, - { ID_VIEWFULLSCREEN, TR("Full &Screen")..KSC(ID_VIEWFULLSCREEN), TR("Switch to or from full screen mode") }, -} - -do -- Add zoom submenu - local zoomMenu = wx.wxMenu{ - {ID_ZOOMRESET, TR("Zoom to 100%")..KSC(ID_ZOOMRESET)}, - {ID_ZOOMIN, TR("Zoom In")..KSC(ID_ZOOMIN)}, - {ID_ZOOMOUT, TR("Zoom Out")..KSC(ID_ZOOMOUT)}, - } - - frame:Connect(ID_ZOOMRESET, wx.wxEVT_COMMAND_MENU_SELECTED, - function() local editor = GetEditorWithFocus() - if editor then editor:SetZoom(0) end end) - frame:Connect(ID_ZOOMIN, wx.wxEVT_COMMAND_MENU_SELECTED, - function() local editor = GetEditorWithFocus() - if editor then editor:SetZoom(editor:GetZoom()+1) end end) - frame:Connect(ID_ZOOMOUT, wx.wxEVT_COMMAND_MENU_SELECTED, - function() local editor = GetEditorWithFocus() - if editor then editor:SetZoom(editor:GetZoom()-1) end end) - - -- only enable if there is an editor - local iseditor = function (event) event:Enable(GetEditorWithFocus() ~= nil) end - for _, id in ipairs({ID_ZOOMRESET, ID_ZOOMIN, ID_ZOOMOUT}) do - frame:Connect(id, wx.wxEVT_UPDATE_UI, iseditor) - end - - viewMenu:Append(ID_ZOOM, TR("Zoom"), zoomMenu) -end - -menuBar:Append(viewMenu, TR("&View")) - -local panels = { - [ID_VIEWOUTPUT] = "bottomnotebook", - [ID_VIEWFILETREE] = "projpanel", - [ID_VIEWWATCHWINDOW] = "watchpanel", - [ID_VIEWCALLSTACK] = "stackpanel", - [ID_VIEWOUTLINE] = "outlinepanel", - [ID_VIEWMARKERS] = "markerspanel", - [ID_VIEWTOOLBAR] = "toolbar", -} - -local function togglePanel(event) - local panel = panels[event:GetId()] - local pane = uimgr:GetPane(panel) - local shown = not pane:IsShown() - if not shown then pane:BestSize(pane.window:GetSize()) end - pane:Show(shown) - uimgr:Update() - - return shown -end - -local function checkPanel(event) - local pane = uimgr:GetPane(panels[event:GetId()]) - event:Enable(pane:IsOk()) -- disable if doesn't exist - menuBar:Check(event:GetId(), pane:IsOk() and pane:IsShown()) -end - -frame:Connect(ID_VIEWDEFAULTLAYOUT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - uimgr:LoadPerspective(uimgr.defaultPerspective, true) - end) - -frame:Connect(ID_VIEWMINIMIZE, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) ide.frame:Iconize(true) end) - -frame:Connect(ID_VIEWFULLSCREEN, wx.wxEVT_COMMAND_MENU_SELECTED, function () - ShowFullScreen(not frame:IsFullScreen()) - end) -frame:Connect(ID_VIEWFULLSCREEN, wx.wxEVT_UPDATE_UI, - function (event) event:Enable(GetEditor() ~= nil) end) - -frame:Connect(ID_VIEWOUTPUT, wx.wxEVT_COMMAND_MENU_SELECTED, togglePanel) -frame:Connect(ID_VIEWFILETREE, wx.wxEVT_COMMAND_MENU_SELECTED, togglePanel) -frame:Connect(ID_VIEWTOOLBAR, wx.wxEVT_COMMAND_MENU_SELECTED, togglePanel) -frame:Connect(ID_VIEWOUTLINE, wx.wxEVT_COMMAND_MENU_SELECTED, togglePanel) -frame:Connect(ID_VIEWMARKERS, wx.wxEVT_COMMAND_MENU_SELECTED, togglePanel) -frame:Connect(ID_VIEWWATCHWINDOW, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) if togglePanel(event) then DebuggerRefreshPanels() end end) -frame:Connect(ID_VIEWCALLSTACK, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) if togglePanel(event) then DebuggerRefreshPanels() end end) - -frame:Connect(ID_VIEWSTATUSBAR, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - frame:GetStatusBar():Show(menuBar:IsChecked(event:GetId())) - uimgr:Update() - end) -frame:Connect(ID_VIEWSTATUSBAR, wx.wxEVT_UPDATE_UI, - function (event) menuBar:Check(event:GetId(), frame:GetStatusBar():IsShown()) end) - -for id in pairs(panels) do frame:Connect(id, wx.wxEVT_UPDATE_UI, checkPanel) end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/outline.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/outline.lua deleted file mode 100644 index cc1fbac..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/outline.lua +++ /dev/null @@ -1,679 +0,0 @@ --- Copyright 2014-15 Paul Kulchenko, ZeroBrane LLC - -local ide = ide -ide.outline = { - outlineCtrl = nil, - imglist = ide:CreateImageList("OUTLINE", "FILE-NORMAL", "VALUE-LCALL", - "VALUE-GCALL", "VALUE-ACALL", "VALUE-SCALL", "VALUE-MCALL"), - settings = { - symbols = {}, - ignoredirs = {}, - }, - needsaving = false, - indexqueue = {[0] = {}}, - indexpurged = false, -- flag that the index has been purged from old records; once per session -} - -local outline = ide.outline -local image = { FILE = 0, LFUNCTION = 1, GFUNCTION = 2, AFUNCTION = 3, - SMETHOD = 4, METHOD = 5, -} -local q = EscapeMagic -local caches = {} - -local function setData(ctrl, item, value) - if ide.wxver >= "2.9.5" then - local data = wx.wxLuaTreeItemData() - data:SetData(value) - ctrl:SetItemData(item, data) - end -end - -local function resetOutlineTimer() - if ide.config.outlineinactivity then - ide.timers.outline:Start(ide.config.outlineinactivity*1000, wx.wxTIMER_ONE_SHOT) - end -end - -local function resetIndexTimer(interval) - if ide.config.symbolindexinactivity and not ide.timers.symbolindex:IsRunning() then - ide.timers.symbolindex:Start(interval or ide.config.symbolindexinactivity*1000, wx.wxTIMER_ONE_SHOT) - end -end - -local function outlineRefresh(editor, force) - if not editor then return end - local tokens = editor:GetTokenList() - local sep = editor.spec.sep - local varname = "([%w_][%w_"..q(sep:sub(1,1)).."]*)" - local funcs = {updated = TimeGet()} - local var = {} - local outcfg = ide.config.outline or {} - local scopes = {} - local funcnum = 0 - local SCOPENUM, FUNCNUM = 1, 2 - local text - for _, token in ipairs(tokens) do - local op = token[1] - if op == 'Var' or op == 'Id' then - var = {name = token.name, fpos = token.fpos, global = token.context[token.name] == nil} - elseif outcfg.showcurrentfunction and op == 'Scope' then - local fundepth = #scopes - if token.name == '(' then -- a function starts a new scope - funcnum = funcnum + 1 -- increment function count - local nested = fundepth == 0 or scopes[fundepth][SCOPENUM] > 0 - scopes[fundepth + (nested and 1 or 0)] = {1, funcnum} - elseif fundepth > 0 then - scopes[fundepth][SCOPENUM] = scopes[fundepth][SCOPENUM] + 1 - end - elseif outcfg.showcurrentfunction and op == 'EndScope' then - local fundepth = #scopes - if fundepth > 0 and scopes[fundepth][SCOPENUM] > 0 then - scopes[fundepth][SCOPENUM] = scopes[fundepth][SCOPENUM] - 1 - if scopes[fundepth][SCOPENUM] == 0 then - local funcnum = scopes[fundepth][FUNCNUM] - if funcs[funcnum] then - funcs[funcnum].poe = token.fpos + (token.name and #token.name or 0) - end - table.remove(scopes) - end - end - elseif op == 'Function' then - local depth = token.context['function'] or 1 - local name, pos = token.name, token.fpos - text = text or editor:GetTextDyn() - local _, _, rname, params = text:find('([^%(]*)(%b())', pos) - if name and rname:find(token.name, 1, true) ~= 1 then - name = rname:gsub("%s+$","") - end - if not name then - local s = editor:PositionFromLine(editor:LineFromPosition(pos-1)) - local rest - rest, pos, name = text:sub(s+1, pos-1):match('%s*(.-)()'..varname..'%s*=%s*function%s*$') - if rest then - pos = s + pos - -- guard against "foo, bar = function() end" as it would get "bar" - if #rest>0 and rest:find(',') then name = nil end - end - end - local ftype = image.LFUNCTION - if not name then - ftype = image.AFUNCTION - elseif outcfg.showmethodindicator and name:find('['..q(sep)..']') then - ftype = name:find(q(sep:sub(1,1))) and image.SMETHOD or image.METHOD - elseif var.name == name and var.fpos == pos - or var.name and name:find('^'..var.name..'['..q(sep)..']') then - ftype = var.global and image.GFUNCTION or image.LFUNCTION - end - name = name or outcfg.showanonymous - funcs[#funcs+1] = { - name = ((name or '~')..params):gsub("%s+", " "), - skip = (not name) and true or nil, - depth = depth, - image = ftype, - pos = name and pos or token.fpos, - } - end - end - - if force == nil then return funcs end - - local ctrl = outline.outlineCtrl - local cache = caches[editor] or {} - caches[editor] = cache - - -- add file - local filename = ide:GetDocument(editor):GetTabText() - local fileitem = cache.fileitem - if not fileitem then - local root = ctrl:GetRootItem() - if not root or not root:IsOk() then return end - - if outcfg.showonefile then - fileitem = root - else - fileitem = ctrl:AppendItem(root, filename, image.FILE) - setData(ctrl, fileitem, editor) - ctrl:SetItemBold(fileitem, true) - ctrl:SortChildren(root) - end - cache.fileitem = fileitem - end - - do -- check if any changes in the cached function list - local prevfuncs = cache.funcs or {} - local nochange = #funcs == #prevfuncs - local resort = {} -- items that need to be re-sorted - if nochange then - for n, func in ipairs(funcs) do - func.item = prevfuncs[n].item -- carry over cached items - if func.depth ~= prevfuncs[n].depth then - nochange = false - elseif nochange and prevfuncs[n].item then - if func.name ~= prevfuncs[n].name then - ctrl:SetItemText(prevfuncs[n].item, func.name) - if outcfg.sort then resort[ctrl:GetItemParent(prevfuncs[n].item)] = true end - end - if func.image ~= prevfuncs[n].image then - ctrl:SetItemImage(prevfuncs[n].item, func.image) - end - end - end - end - cache.funcs = funcs -- set new cache as positions may change - if nochange and not force then -- return if no visible changes - if outcfg.sort then -- resort items for all parents that have been modified - for item in pairs(resort) do ctrl:SortChildren(item) end - end - return - end - end - - -- refresh the tree - -- refreshing shouldn't change the focus of the current element, - -- but it appears that DeleteChildren (wxwidgets 2.9.5 on Windows) - -- moves the focus from the current element to wxTreeCtrl. - -- need to save the window having focus and restore after the refresh. - local win = ide:GetMainFrame():FindFocus() - - ctrl:Freeze() - - -- disabling event handlers is not strictly necessary, but it's expected - -- to fix a crash on Windows that had DeleteChildren in the trace (#442). - ctrl:SetEvtHandlerEnabled(false) - ctrl:DeleteChildren(fileitem) - ctrl:SetEvtHandlerEnabled(true) - - local edpos = editor:GetCurrentPos()+1 - local stack = {fileitem} - local resort = {} -- items that need to be re-sorted - for n, func in ipairs(funcs) do - local depth = outcfg.showflat and 1 or func.depth - local parent = stack[depth] - while not parent do depth = depth - 1; parent = stack[depth] end - if not func.skip then - local item = ctrl:AppendItem(parent, func.name, func.image) - if ide.config.outline.showcurrentfunction - and edpos >= func.pos and func.poe and edpos <= func.poe then - ctrl:SetItemBold(item, true) - end - if outcfg.sort then resort[parent] = true end - setData(ctrl, item, n) - func.item = item - stack[func.depth+1] = item - end - func.skip = nil - end - if outcfg.sort then -- resort items for all parents that have been modified - for item in pairs(resort) do ctrl:SortChildren(item) end - end - if outcfg.showcompact then ctrl:Expand(fileitem) else ctrl:ExpandAllChildren(fileitem) end - - -- scroll to the fileitem, but only if it's not a root item (as it's hidden) - if fileitem:GetValue() ~= ctrl:GetRootItem():GetValue() then - ctrl:ScrollTo(fileitem) - ctrl:SetScrollPos(wx.wxHORIZONTAL, 0, true) - else -- otherwise, scroll to the top - ctrl:SetScrollPos(wx.wxVERTICAL, 0, true) - end - ctrl:Thaw() - - if win and win ~= ide:GetMainFrame():FindFocus() then win:SetFocus() end -end - -local function indexFromQueue() - if #outline.indexqueue == 0 then return end - - local editor = ide:GetEditor() - local inactivity = ide.config.symbolindexinactivity - if editor and inactivity and editor.updated > TimeGet()-inactivity then - -- reschedule timer for later time - resetIndexTimer() - else - local fname = table.remove(outline.indexqueue, 1) - outline.indexqueue[0][fname] = nil - -- check if fname is already loaded - ide:SetStatusFor(TR("Indexing %d files: '%s'..."):format(#outline.indexqueue+1, fname)) - local content, err = FileRead(fname) - if content then - local editor = ide:CreateBareEditor() - editor:SetupKeywords(GetFileExt(fname)) - editor:SetTextDyn(content) - editor:Colourise(0, -1) - editor:ResetTokenList() - while IndicateAll(editor) do end - - outline:UpdateSymbols(fname, outlineRefresh(editor)) - editor:Destroy() - else - DisplayOutputLn(TR("Can't open file '%s': %s"):format(fname, err)) - end - if #outline.indexqueue == 0 then - outline:SaveSettings() - ide:SetStatusFor(TR("Indexing completed.")) - end - ide:DoWhenIdle(indexFromQueue) - end - return -end - -local function createOutlineWindow() - local REFRESH, REINDEX = 1, 2 - local width, height = 360, 200 - local ctrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxSize(width, height), - wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS - + wx.wxTR_HIDE_ROOT + wx.wxNO_BORDER) - - outline.outlineCtrl = ctrl - ide.timers.outline = wx.wxTimer(ctrl, REFRESH) - ide.timers.symbolindex = wx.wxTimer(ctrl, REINDEX) - - ctrl:AddRoot("Outline") - ctrl:SetImageList(outline.imglist) - ctrl:SetFont(ide.font.fNormal) - - function ctrl:ActivateItem(item_id) - local data = ctrl:GetItemData(item_id) - if ctrl:GetItemImage(item_id) == image.FILE then - -- activate editor tab - local editor = data:GetData() - if not ide:GetEditorWithFocus(editor) then ide:GetDocument(editor):SetActive() end - else - -- activate tab and move cursor based on stored pos - -- get file parent - local onefile = (ide.config.outline or {}).showonefile - local parent = ctrl:GetItemParent(item_id) - if not onefile then -- find the proper parent - while parent:IsOk() and ctrl:GetItemImage(parent) ~= image.FILE do - parent = ctrl:GetItemParent(parent) - end - if not parent:IsOk() then return end - end - -- activate editor tab - local editor = onefile and GetEditor() or ctrl:GetItemData(parent):GetData() - local cache = caches[editor] - if editor and cache then - -- move to position in the file - editor:GotoPosEnforcePolicy(cache.funcs[data:GetData()].pos-1) - -- only set editor active after positioning as this may change focus, - -- which may regenerate the outline, which may invalidate `data` value - if not ide:GetEditorWithFocus(editor) then ide:GetDocument(editor):SetActive() end - end - end - end - - local function activateByPosition(event) - local mask = (wx.wxTREE_HITTEST_ONITEMINDENT + wx.wxTREE_HITTEST_ONITEMLABEL - + wx.wxTREE_HITTEST_ONITEMICON + wx.wxTREE_HITTEST_ONITEMRIGHT) - local item_id, flags = ctrl:HitTest(event:GetPosition()) - - if item_id and item_id:IsOk() and bit.band(flags, mask) > 0 then - ctrl:ActivateItem(item_id) - else - event:Skip() - end - return true - end - - ctrl:Connect(wx.wxEVT_TIMER, function(event) - if event:GetId() == REFRESH then outlineRefresh(GetEditor(), false) end - if event:GetId() == REINDEX then ide:DoWhenIdle(indexFromQueue) end - end) - ctrl:Connect(wx.wxEVT_LEFT_DOWN, activateByPosition) - ctrl:Connect(wx.wxEVT_LEFT_DCLICK, activateByPosition) - ctrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED, function(event) - ctrl:ActivateItem(event:GetItem()) - end) - - ctrl:Connect(ID_OUTLINESORT, wx.wxEVT_COMMAND_MENU_SELECTED, - function() - ide.config.outline.sort = not ide.config.outline.sort - for editor, cache in pairs(caches) do - ide:SetStatus(("Refreshing '%s'..."):format(ide:GetDocument(editor):GetFileName())) - local isexpanded = ctrl:IsExpanded(cache.fileitem) - outlineRefresh(editor, true) - if not isexpanded then ctrl:Collapse(cache.fileitem) end - end - ide:SetStatus('') - end) - - ctrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_MENU, - function (event) - local menu = wx.wxMenu { - { ID_OUTLINESORT, TR("Sort By Name"), "", wx.wxITEM_CHECK }, - } - menu:Check(ID_OUTLINESORT, ide.config.outline.sort) - - PackageEventHandle("onMenuOutline", menu, ctrl, event) - - ctrl:PopupMenu(menu) - end) - - - local function reconfigure(pane) - pane:TopDockable(false):BottomDockable(false) - :MinSize(150,-1):BestSize(300,-1):FloatingSize(200,300) - end - - local layout = ide:GetSetting("/view", "uimgrlayout") - if not layout or not layout:find("outlinepanel") then - ide:AddPanelDocked(ide:GetProjectNotebook(), ctrl, "outlinepanel", TR("Outline"), reconfigure, false) - else - ide:AddPanel(ctrl, "outlinepanel", TR("Outline"), reconfigure) - end -end - -local function eachNode(eachFunc, root, recursive) - local ctrl = outline.outlineCtrl - local item = ctrl:GetFirstChild(root or ctrl:GetRootItem()) - while true do - if not item:IsOk() then break end - if eachFunc and eachFunc(ctrl, item) then break end - if recursive and ctrl:ItemHasChildren(item) then eachNode(eachFunc, item, recursive) end - item = ctrl:GetNextSibling(item) - end -end - -createOutlineWindow() - -local pathsep = GetPathSeparator() -local function isInSubDir(name, path) - return #name > #path and path..pathsep == name:sub(1, #path+#pathsep) -end - -local function isIgnoredInIndex(name) - local ignoredirs = outline.settings.ignoredirs - if ignoredirs[name] then return true end - - -- check through ignored dirs to see if any of them match the file - for path in pairs(ignoredirs) do - if isInSubDir(name, path) then return true end - end - - return false -end - -local function purgeIndex(path) - local symbols = outline.settings.symbols - for name in pairs(symbols) do - if isInSubDir(name, path) then outline:UpdateSymbols(name, nil) end - end -end - -local function purgeQueue(path) - local curqueue = outline.indexqueue - local newqueue = {[0] = {}} - for _, name in ipairs(curqueue) do - if not isInSubDir(name, path) then - table.insert(newqueue, name) - newqueue[0][name] = true - end - end - outline.indexqueue = newqueue -end - -local function disableIndex(path) - outline.settings.ignoredirs[path] = true - outline:SaveSettings(true) - - -- purge the path from the index and the (current) queue - purgeIndex(path) - purgeQueue(path) -end - -local function enableIndex(path) - outline.settings.ignoredirs[path] = nil - outline:SaveSettings(true) - outline:RefreshSymbols(path) -end - -local package = ide:AddPackage('core.outline', { - -- remove the editor from the list - onEditorClose = function(self, editor) - local cache = caches[editor] - local fileitem = cache and cache.fileitem - caches[editor] = nil -- remove from cache - if (ide.config.outline or {}).showonefile then return end - if fileitem then outline.outlineCtrl:Delete(fileitem) end - end, - - -- handle rename of the file in the current editor - onEditorSave = function(self, editor) - if (ide.config.outline or {}).showonefile then return end - local cache = caches[editor] - local fileitem = cache and cache.fileitem - local doc = ide:GetDocument(editor) - local ctrl = outline.outlineCtrl - if doc and fileitem and ctrl:GetItemText(fileitem) ~= doc:GetTabText() then - ctrl:SetItemText(fileitem, doc:GetTabText()) - end - local path = doc and doc:GetFilePath() - if path and cache and cache.funcs then - outline:UpdateSymbols(path, cache.funcs.updated > editor.updated and cache.funcs or nil) - outline:SaveSettings() - end - end, - - -- go over the file items to turn bold on/off or collapse/expand - onEditorFocusSet = function(self, editor) - if (ide.config.outline or {}).showonefile and ide.config.outlineinactivity then - outlineRefresh(editor, true) - return - end - - local cache = caches[editor] - local fileitem = cache and cache.fileitem - local ctrl = outline.outlineCtrl - local itemname = ide:GetDocument(editor):GetTabText() - - -- update file name if it changed in the editor - if fileitem and ctrl:GetItemText(fileitem) ~= itemname then - ctrl:SetItemText(fileitem, itemname) - end - - -- if the editor is not in the cache, which may happen if the user - -- quickly switches between tabs that don't have outline generated, - -- regenerate it manually - if not cache then resetOutlineTimer() end - resetIndexTimer() - - eachNode(function(ctrl, item) - local found = fileitem and item:GetValue() == fileitem:GetValue() - if not found and ctrl:IsBold(item) then - ctrl:SetItemBold(item, false) - ctrl:CollapseAllChildren(item) - end - end) - - if fileitem and not ctrl:IsBold(fileitem) then - -- run the following changes on idle as doing them inline is causing a strange - -- issue on OSX when clicking on a tab may skip several tabs (#546); - -- this is somehow caused by `ExpandAllChildren` triggered from `SetFocus` inside - -- `PAGE_CHANGED` handler for the notebook. - ide:DoWhenIdle(function() - ctrl:SetItemBold(fileitem, true) - if (ide.config.outline or {}).showcompact then - ctrl:Expand(fileitem) - else - ctrl:ExpandAllChildren(fileitem) - end - ctrl:ScrollTo(fileitem) - ctrl:SetScrollPos(wx.wxHORIZONTAL, 0, true) - end) - end - end, - - onMenuFiletree = function(self, menu, tree, event) - local item_id = event:GetItem() - local name = tree:GetItemFullName(item_id) - local symboldirmenu = wx.wxMenu { - {ID_SYMBOLDIRREFRESH, TR("Refresh Index"), TR("Refresh indexed symbols from files in the selected directory")}, - {ID_SYMBOLDIRDISABLE, TR("Disable Indexing For '%s'"):format(name), TR("Ignore and don't index symbols from files in the selected directory")}, - } - local _, _, projdirpos = ide:FindMenuItem(ID_PROJECTDIR, menu) - if projdirpos then - local ignored = isIgnoredInIndex(name) - local enabledirmenu = wx.wxMenu() - local paths = {} - for path in pairs(outline.settings.ignoredirs) do table.insert(paths, path) end - table.sort(paths) - for i, path in ipairs(paths) do - local id = ID("file.enablesymboldir."..i) - enabledirmenu:Append(id, path, "") - tree:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function() enableIndex(path) end) - end - - symboldirmenu:Append(wx.wxMenuItem(symboldirmenu, ID_SYMBOLDIRENABLE, - TR("Enable Indexing"), "", wx.wxITEM_NORMAL, enabledirmenu)) - menu:Insert(projdirpos+1, wx.wxMenuItem(menu, ID_SYMBOLDIRINDEX, - TR("Symbol Index"), "", wx.wxITEM_NORMAL, symboldirmenu)) - - -- disable "enable" if it's empty - menu:Enable(ID_SYMBOLDIRENABLE, #paths > 0) - -- disable "refresh" and "disable" if the directory is ignored - -- or if any of the directories above it are ignored - menu:Enable(ID_SYMBOLDIRREFRESH, tree:IsDirectory(item_id) and not ignored) - menu:Enable(ID_SYMBOLDIRDISABLE, tree:IsDirectory(item_id) and not ignored) - - tree:Connect(ID_SYMBOLDIRREFRESH, wx.wxEVT_COMMAND_MENU_SELECTED, function() - -- purge files in this directory as some might have been removed; - -- files will be purged based on time, but this is a good time to clean. - purgeIndex(name) - outline:RefreshSymbols(name) - resetIndexTimer(1) -- start after 1ms - end) - tree:Connect(ID_SYMBOLDIRDISABLE, wx.wxEVT_COMMAND_MENU_SELECTED, function() - disableIndex(name) - end) - end - end, - - onEditorPainted = function(self, editor) - local ctrl = ide.outline.outlineCtrl - if not ide:IsWindowShown(ctrl) then return end - - local cache = caches[editor] - if not cache or not ide.config.outline.showcurrentfunction then return end - - local edpos = editor:GetCurrentPos()+1 - local edline = editor:LineFromPosition(edpos-1)+1 - if cache.pos and cache.pos == edpos then return end - if cache.line and cache.line == edline then return end - - cache.pos = edpos - cache.line = edline - - local n = 0 - local MIN, MAX = 1, 2 - local visible = {[MIN] = math.huge, [MAX] = 0} - local needshown = {[MIN] = math.huge, [MAX] = 0} - - ctrl:Unselect() - -- scan all items recursively starting from the current file - eachNode(function(ctrl, item) - local func = cache.funcs[ctrl:GetItemData(item):GetData()] - local val = edpos >= func.pos and func.poe and edpos <= func.poe - if edline == editor:LineFromPosition(func.pos)+1 - or (func.poe and edline == editor:LineFromPosition(func.poe)+1) then - cache.line = nil - end - ctrl:SetItemBold(item, val) - if val then ctrl:SelectItem(item, val) end - - if not ide.config.outline.jumptocurrentfunction then return end - n = n + 1 - -- check that this and the items around it are all visible; - -- this is to avoid the situation when the current item is only partially visible - local isvisible = ctrl:IsVisible(item) and ctrl:GetNextVisible(item):IsOk() and ctrl:GetPrevVisible(item):IsOk() - if val and not isvisible then - needshown[MIN] = math.min(needshown[MIN], n) - needshown[MAX] = math.max(needshown[MAX], n) - elseif isvisible then - visible[MIN] = math.min(visible[MIN], n) - visible[MAX] = math.max(visible[MAX], n) - end - end, cache.fileitem, true) - - if not ide.config.outline.jumptocurrentfunction then return end - if needshown[MAX] > visible[MAX] then - ctrl:ScrollLines(needshown[MAX]-visible[MAX]) -- scroll forward to the last hidden line - elseif needshown[MIN] < visible[MIN] then - ctrl:ScrollLines(needshown[MIN]-visible[MIN]) -- scroll backward to the first hidden line - end - end, - }) - -local function queuePath(path) - -- only queue if symbols inactivity is set, so files will be indexed - if ide.config.symbolindexinactivity and not outline.indexqueue[0][path] then - outline.indexqueue[0][path] = true - table.insert(outline.indexqueue, 1, path) - end -end - -function outline:GetFileSymbols(path) - local symbols = self.settings.symbols[path] - -- queue path to process when appropriate - if not symbols then queuePath(path) end - return symbols -end - -function outline:GetEditorSymbols(editor) - -- force token refresh (as these may be not updated yet) - if #editor:GetTokenList() == 0 then - while IndicateAll(editor) do end - end - - -- only refresh the functions when none is present - if not caches[editor] or #caches[editor].funcs == 0 then outlineRefresh(editor, true) end - return caches[editor].funcs -end - -function outline:RefreshSymbols(path, callback) - if isIgnoredInIndex(path) then return end - - local exts = {} - for _, ext in pairs(ide:GetKnownExtensions()) do - local spec = GetSpec(ext) - if spec and spec.marksymbols then table.insert(exts, ext) end - end - - local opts = {sort = false, folder = false, skipbinary = true, yield = true, - -- skip those directories that are on the "ignore" list - ondirectory = function(name) return outline.settings.ignoredirs[name] == nil end - } - local nextfile = coroutine.wrap(function() FileSysGetRecursive(path, true, table.concat(exts, ";"), opts) end) - while true do - local file = nextfile() - if not file then break end - if not isIgnoredInIndex(file) then (callback or queuePath)(file) end - end -end - -function outline:UpdateSymbols(fname, symb) - local symbols = self.settings.symbols - symbols[fname] = symb - - -- purge outdated records - local threshold = TimeGet() - 60*60*24*7 -- cache for 7 days - if not self.indexpurged then - for k, v in pairs(symbols) do - if v.updated < threshold then symbols[k] = nil end - end - self.indexpurged = true - end - - self.needsaving = true -end - -function outline:SaveSettings(force) - if self.needsaving or force then - ide:PushStatus(TR("Updating symbol index and settings...")) - package:SetSettings(self.settings, {keyignore = {depth = true, image = true, poe = true, item = true, skip = true}}) - ide:PopStatus() - self.needsaving = false - end -end - -MergeSettings(outline.settings, package:GetSettings()) diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/output.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/output.lua deleted file mode 100644 index 523ac8c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/output.lua +++ /dev/null @@ -1,498 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local frame = ide.frame -local bottomnotebook = frame.bottomnotebook -local errorlog = bottomnotebook.errorlog - -------- --- setup errorlog -local MESSAGE_MARKER = StylesGetMarker("message") -local PROMPT_MARKER = StylesGetMarker("prompt") -local PROMPT_MARKER_VALUE = 2^PROMPT_MARKER - -errorlog:Show(true) -errorlog:SetFont(ide.font.oNormal) -errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal) -errorlog:SetBufferedDraw(not ide.config.hidpi and true or false) -errorlog:StyleClearAll() -errorlog:SetMarginWidth(1, 16) -- marker margin -errorlog:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL) -errorlog:MarkerDefine(StylesGetMarker("message")) -errorlog:MarkerDefine(StylesGetMarker("prompt")) -errorlog:SetReadOnly(true) -if (ide.config.outputshell.usewrap) then - errorlog:SetWrapMode(wxstc.wxSTC_WRAP_WORD) - errorlog:SetWrapStartIndent(0) - errorlog:SetWrapVisualFlags(wxstc.wxSTC_WRAPVISUALFLAG_END) - errorlog:SetWrapVisualFlagsLocation(wxstc.wxSTC_WRAPVISUALFLAGLOC_END_BY_TEXT) -end - -StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic) - -function ClearOutput(force) - if not (force or ide:GetMenuBar():IsChecked(ID_CLEAROUTPUT)) then return end - errorlog:SetReadOnly(false) - errorlog:ClearAll() - errorlog:SetReadOnly(true) -end - -local inputBound = 0 -- to track where partial output ends for input editing purposes -local function getInputLine() - return errorlog:MarkerPrevious(errorlog:GetLineCount()+1, PROMPT_MARKER_VALUE) -end -local function getInputText(bound) - return errorlog:GetTextRangeDyn( - errorlog:PositionFromLine(getInputLine())+(bound or 0), errorlog:GetLength()) -end -local function updateInputMarker() - local lastline = errorlog:GetLineCount()-1 - errorlog:MarkerDeleteAll(PROMPT_MARKER) - errorlog:MarkerAdd(lastline, PROMPT_MARKER) - inputBound = #getInputText() -end -function OutputEnableInput() updateInputMarker() end - -function DisplayOutputNoMarker(...) - local message = "" - local cnt = select('#',...) - for i=1,cnt do - local v = select(i,...) - message = message..tostring(v)..(i 0 and pidAssign or nil - end - if pid and winapi then - local now = TimeGet() - if pidAssign and pidAssign > 0 then - checkstart, checknext, checkperiod = now, now, 0.02 - end - if now - checkstart > 1 and checkperiod < 0.5 then - checkperiod = checkperiod * 2 - end - if now >= checknext then - checknext = now + checkperiod - else - return - end - local wins = winapi.find_all_windows(function(w) - return w:get_process():get_pid() == pid - end) - local any = ide.interpreter.unhideanywindow - local show, hide, ignore = 1, 2, 0 - for _,win in pairs(wins) do - -- win:get_class_name() can return nil if the window is already gone - -- between getting the list and this check. - local action = ide.config.unhidewindow[win:get_class_name()] - or (any and show or ignore) - if action == show and not win:is_visible() - or action == hide and win:is_visible() then - -- use show_async call (ShowWindowAsync) to avoid blocking the IDE - -- if the app is busy or is being debugged - win:show_async(action == show and winapi.SW_SHOW or winapi.SW_HIDE) - pid = nil -- indicate that unhiding is done - end - end - end -end - -local function nameTab(tab, name) - local index = bottomnotebook:GetPageIndex(tab) - if index ~= -1 then bottomnotebook:SetPageText(index, name) end -end - -function OutputSetCallbacks(pid, proc, callback, endcallback) - local streamin = proc and proc:GetInputStream() - local streamerr = proc and proc:GetErrorStream() - if streamin then - streamins[pid] = {stream=streamin, callback=callback, - proc=proc, check=proc and proc.IsInputAvailable} - end - if streamerr then - streamerrs[pid] = {stream=streamerr, callback=callback, - proc=proc, check=proc and proc.IsErrorAvailable} - end - customprocs[pid] = {proc=proc, endcallback=endcallback} -end - -function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback) - if (not cmd) then return end - - -- expand ~ at the beginning of the command - if ide.oshome and cmd:find('~') then - cmd = cmd:gsub([[^(['"]?)~]], '%1'..ide.oshome:gsub('[\\/]$',''), 1) - end - - -- try to extract the name of the executable from the command - -- the executable may not have the extension and may be in quotes - local exename = string.gsub(cmd, "\\", "/") - local _,_,fullname = string.find(exename,'^[\'"]([^\'"]+)[\'"]') - exename = fullname and string.match(fullname,'/?([^/]+)$') - or string.match(exename,'/?([^/]-)%s') or exename - - uid = uid or exename - - if (CommandLineRunning(uid)) then - DisplayOutputLn(TR("Program can't start because conflicting process is running as '%s'.") - :format(cmd)) - return - end - - DisplayOutputLn(TR("Program starting as '%s'."):format(cmd)) - - local proc = wx.wxProcess(errorlog) - if (tooutput) then proc:Redirect() end -- redirect the output if requested - - -- set working directory if specified - local oldcwd - if (wdir and #wdir > 0) then -- directory can be empty; ignore in this case - oldcwd = wx.wxFileName.GetCwd() - oldcwd = wx.wxFileName.SetCwd(wdir) and oldcwd - end - - -- launch process - local params = wx.wxEXEC_ASYNC + wx.wxEXEC_MAKE_GROUP_LEADER + (nohide and wx.wxEXEC_NOHIDE or 0) - local pid = wx.wxExecute(cmd, params, proc) - - if oldcwd then wx.wxFileName.SetCwd(oldcwd) end - - -- For asynchronous execution, the return value is the process id and - -- zero value indicates that the command could not be executed. - -- The return value of -1 in this case indicates that we didn't launch - -- a new process, but connected to the running one (e.g. DDE under Windows). - if not pid or pid == -1 or pid == 0 then - DisplayOutputLn(TR("Program unable to run as '%s'."):format(cmd)) - return - end - - DisplayOutputLn(TR("Program '%s' started in '%s' (pid: %d).") - :format(uid, (wdir and wdir or wx.wxFileName.GetCwd()), pid)) - - OutputSetCallbacks(pid, proc, stringcallback, endcallback) - customprocs[pid].uid=uid - customprocs[pid].started = TimeGet() - - local streamout = proc and proc:GetOutputStream() - if streamout then streamouts[pid] = {stream=streamout, callback=stringcallback, out=true} end - - unHideWindow(pid) - nameTab(errorlog, TR("Output (running)")) - - return pid -end - -local readonce = 4096 -local maxread = readonce * 10 -- maximum number of bytes to read before pausing -local function getStreams() - local function readStream(tab) - for _,v in pairs(tab) do - -- periodically stop reading to get a chance to process other events - local processed = 0 - while (v.check(v.proc) and processed <= maxread) do - local str = v.stream:Read(readonce) - -- the buffer has readonce bytes, so cut it to the actual size - str = str:sub(1, v.stream:LastRead()) - processed = processed + #str - - local pfn - if (v.callback) then - str,pfn = v.callback(str) - end - if not str then - -- skip if nothing to display - elseif (v.toshell) then - DisplayShell(str) - else - DisplayOutputNoMarker(str) - if str and (getInputLine() > -1 or errorlog:GetReadOnly()) then - ActivateOutput() - updateInputMarker() - end - end - pfn = pfn and pfn() - end - end - end - local function sendStream(tab) - local str = textout - if not str then return end - textout = nil - str = str .. "\n" - for _,v in pairs(tab) do - local pfn - if (v.callback) then - str,pfn = v.callback(str) - end - v.stream:Write(str, #str) - updateInputMarker() - pfn = pfn and pfn() - end - end - - readStream(streamins) - readStream(streamerrs) - sendStream(streamouts) -end - -errorlog:Connect(wx.wxEVT_END_PROCESS, function(event) - local pid = event:GetPid() - if (pid ~= -1) then - getStreams() - streamins[pid] = nil - streamerrs[pid] = nil - streamouts[pid] = nil - - if not customprocs[pid] then return end - if customprocs[pid].endcallback then customprocs[pid].endcallback() end - -- if this wasn't started with CommandLineRun, skip the rest - if not customprocs[pid].uid then return end - - -- delete markers and set focus to the editor if there is an input marker - if errorlog:MarkerPrevious(errorlog:GetLineCount(), PROMPT_MARKER_VALUE) > -1 then - errorlog:MarkerDeleteAll(PROMPT_MARKER) - local editor = GetEditor() - -- check if editor still exists; it may not if the window is closed - if editor then editor:SetFocus() end - end - unHideWindow(0) - DebuggerStop(true) - nameTab(errorlog, TR("Output")) - DisplayOutputLn(TR("Program completed in %.2f seconds (pid: %d).") - :format(TimeGet() - customprocs[pid].started, pid)) - customprocs[pid] = nil - end - end) - -errorlog:Connect(wx.wxEVT_IDLE, function() - if (#streamins or #streamerrs) then getStreams() end - if ide.osname == 'Windows' then unHideWindow() end - end) - -local jumptopatterns = { - -- (line,linepos): - "^%s*(.-)%((%d+),(%d+)%)%s*:", - -- (line): - "^%s*(.-)%((%d+).*%)%s*:", - --[string ""]:line: - '^.-%[string "([^"]+)"%]:(%d+)%s*:', - -- :line:linepos - "^%s*(.-):(%d+):(%d+):", - -- :line: - "^%s*(.-):(%d+)%s*:", -} - -errorlog:Connect(wxstc.wxEVT_STC_DOUBLECLICK, - function(event) - local line = errorlog:GetCurrentLine() - local linetx = errorlog:GetLineDyn(line) - - -- try to detect a filename and line in linetx - local fname, jumpline, jumplinepos - for _,pattern in ipairs(jumptopatterns) do - fname,jumpline,jumplinepos = linetx:match(pattern) - if (fname and jumpline) then break end - end - - if not (fname and jumpline) then return end - - -- fname may include name of executable, as in "path/to/lua: file.lua"; - -- strip it and try to find match again if needed. - -- try the stripped name first as if it doesn't match, the longer - -- name may have parts that may be interpreter as network path and - -- may take few seconds to check. - local name - local fixedname = fname:match(":%s+(.+)") - if fixedname then - name = GetFullPathIfExists(FileTreeGetDir(), fixedname) - or FileTreeFindByPartialName(fixedname) - end - name = name - or GetFullPathIfExists(FileTreeGetDir(), fname) - or FileTreeFindByPartialName(fname) - - local editor = LoadFile(name or fname,nil,true) - if not editor then - local ed = GetEditor() - if ed and ide:GetDocument(ed):GetFileName() == (name or fname) then - editor = ed - end - end - if editor then - jumpline = tonumber(jumpline) - jumplinepos = tonumber(jumplinepos) - - editor:GotoPos(editor:PositionFromLine(math.max(0,jumpline-1)) - + (jumplinepos and (math.max(0,jumplinepos-1)) or 0)) - editor:EnsureVisibleEnforcePolicy(jumpline) - editor:SetFocus() - end - - -- doubleclick can set selection, so reset it - local pos = event:GetPosition() - if pos == -1 then pos = errorlog:GetLineEndPosition(event:GetLine()) end - errorlog:SetSelection(pos, pos) - end) - -local function positionInLine(line) - return errorlog:GetCurrentPos() - errorlog:PositionFromLine(line) -end -local function caretOnInputLine(disallowLeftmost) - local inputLine = getInputLine() - local boundary = inputBound + (disallowLeftmost and 0 or -1) - return (errorlog:GetCurrentLine() > inputLine - or errorlog:GetCurrentLine() == inputLine - and positionInLine(inputLine) > boundary) -end - -errorlog:Connect(wx.wxEVT_KEY_DOWN, - function (event) - -- this loop is only needed to allow to get to the end of function easily - -- "return" aborts the processing and ignores the key - -- "break" aborts the processing and processes the key normally - while true do - -- no special processing if it's readonly - if errorlog:GetReadOnly() then break end - - local key = event:GetKeyCode() - if key == wx.WXK_UP or key == wx.WXK_NUMPAD_UP then - if errorlog:GetCurrentLine() > getInputLine() then break - else return end - elseif key == wx.WXK_DOWN or key == wx.WXK_NUMPAD_DOWN then - break -- can go down - elseif key == wx.WXK_LEFT or key == wx.WXK_NUMPAD_LEFT then - if not caretOnInputLine(true) then return end - elseif key == wx.WXK_BACK then - if not caretOnInputLine(true) then return end - elseif key == wx.WXK_DELETE or key == wx.WXK_NUMPAD_DELETE then - if not caretOnInputLine() - or errorlog:LineFromPosition(errorlog:GetSelectionStart()) < getInputLine() then - return - end - elseif key == wx.WXK_PAGEUP or key == wx.WXK_NUMPAD_PAGEUP - or key == wx.WXK_PAGEDOWN or key == wx.WXK_NUMPAD_PAGEDOWN - or key == wx.WXK_END or key == wx.WXK_NUMPAD_END - or key == wx.WXK_HOME or key == wx.WXK_NUMPAD_HOME - or key == wx.WXK_RIGHT or key == wx.WXK_NUMPAD_RIGHT - or key == wx.WXK_SHIFT or key == wx.WXK_CONTROL - or key == wx.WXK_ALT then - break - elseif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER then - if not caretOnInputLine() - or errorlog:LineFromPosition(errorlog:GetSelectionStart()) < getInputLine() then - return - end - errorlog:GotoPos(errorlog:GetLength()) -- move to the end - textout = (textout or '') .. getInputText(inputBound) - -- remove selection if any, otherwise the text gets replaced - errorlog:SetSelection(errorlog:GetSelectionEnd()+1,errorlog:GetSelectionEnd()) - break -- don't need to do anything else with return - else - -- move cursor to end if not already there - if not caretOnInputLine() then - errorlog:GotoPos(errorlog:GetLength()) - -- check if the selection starts before the input line and reset it - elseif errorlog:LineFromPosition(errorlog:GetSelectionStart()) < getInputLine(-1) then - errorlog:GotoPos(errorlog:GetLength()) - errorlog:SetSelection(errorlog:GetSelectionEnd()+1,errorlog:GetSelectionEnd()) - end - end - break - end - event:Skip() - end) - -local function inputEditable(line) - local inputLine = getInputLine() - local currentLine = line or errorlog:GetCurrentLine() - return inputLine > -1 and - (currentLine > inputLine or - currentLine == inputLine and positionInLine(inputLine) >= inputBound) and - not (errorlog:LineFromPosition(errorlog:GetSelectionStart()) < getInputLine()) -end - -errorlog:Connect(wxstc.wxEVT_STC_UPDATEUI, - function () errorlog:SetReadOnly(not inputEditable()) end) - --- only allow copy/move text by dropping to the input line -errorlog:Connect(wxstc.wxEVT_STC_DO_DROP, - function (event) - if not inputEditable(errorlog:LineFromPosition(event:GetPosition())) then - event:SetDragResult(wx.wxDragNone) - end - end) - -if ide.config.outputshell.nomousezoom then - -- disable zoom using mouse wheel as it triggers zooming when scrolling - -- on OSX with kinetic scroll and then pressing CMD. - errorlog:Connect(wx.wxEVT_MOUSEWHEEL, - function (event) - if wx.wxGetKeyState(wx.WXK_CONTROL) then return end - event:Skip() - end) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/package.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/package.lua deleted file mode 100644 index 004bcd0..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/package.lua +++ /dev/null @@ -1,735 +0,0 @@ --- Copyright 2013-15 Paul Kulchenko, ZeroBrane LLC ---------------------------------------------------------- - -local ide = ide -local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a")) -local unpack = table.unpack or unpack -local q = EscapeMagic - -local function eventHandle(handlers, event, ...) - local success - for package, handler in pairs(handlers) do - local ok, res = pcall(handler, package, ...) - if ok then - if res == false then success = false end - else - DisplayOutputLn(TR("%s event failed: %s"):format(event, res)) - end - end - return success -end - -local function getEventHandlers(packages, event) - local handlers = {} - for _, package in pairs(packages) do - if package[event] then handlers[package] = package[event] end - end - return handlers -end - -function PackageEventHandle(event, ...) - return eventHandle(getEventHandlers(ide.packages, event), event, ...) -end - -function PackageEventHandleOnce(event, ...) - -- copy packages as the event that is handled only once needs to be removed - local handlers = getEventHandlers(ide.packages, event) - -- remove all handlers as they need to be called only once - -- this allows them to be re-installed if needed - for _, package in pairs(ide.packages) do package[event] = nil end - return eventHandle(handlers, event, ...) -end - -local function PackageEventHandleOne(file, event, ...) - local package = ide.packages[file] - if package and type(package[event]) == 'function' then - local ok, res = pcall(package[event], package, ...) - if ok then - if res == false then return false end - else - DisplayOutputLn(TR("%s event failed: %s"):format(event, res)) - end - end -end - -function PackageUnRegister(file, ...) - PackageEventHandleOne(file, "onUnRegister", ...) - -- remove from the list of installed packages - local package = ide.packages[file] - ide.packages[file] = nil - return package -end - -function PackageRegister(file, ...) - if not ide.packages[file] then - local packages = {} - local package = MergeFullPath( - GetPathWithSep(ide.editorFilename), "packages/"..file..".lua") - LoadLuaFileExt(packages, package, ide.proto.Plugin) - packages[file].fname = file - ide.packages[file] = packages[file] - end - return PackageEventHandleOne(file, "onRegister", ...) -end - -function ide:GetRootPath(path) - return MergeFullPath(GetPathWithSep(self.editorFilename), path or '') -end -function ide:GetPackagePath(packname) - return MergeFullPath( - self.oshome and MergeFullPath(self.oshome, '.'..self:GetAppName()..'/') or self:GetRootPath(), - MergeFullPath('packages', packname or '') - ) -end -function ide:GetApp() return self.editorApp end -function ide:GetAppName() return self.appname end -function ide:GetEditor(index) return GetEditor(index) end -function ide:GetEditorWithFocus(...) return GetEditorWithFocus(...) end -function ide:GetEditorWithLastFocus() - -- make sure ide.infocus is still a valid component and not "some" userdata - return (self:IsValidCtrl(self.infocus) - and self.infocus:GetClassInfo():GetClassName() == "wxStyledTextCtrl" - and self.infocus:DynamicCast("wxStyledTextCtrl") or nil) -end -function ide:GetMenuBar() return self.frame.menuBar end -function ide:GetStatusBar() return self.frame.statusBar end -function ide:GetToolBar() return self.frame.toolBar end -function ide:GetDebugger() return self.debugger end -function ide:GetMainFrame() return self.frame end -function ide:GetUIManager() return self.frame.uimgr end -function ide:GetDocument(ed) return ed and self.openDocuments[ed:GetId()] end -function ide:GetDocuments() return self.openDocuments end -function ide:GetKnownExtensions(ext) - local knownexts, extmatch = {}, ext and ext:lower() - for _, spec in pairs(self.specs) do - for _, ext in ipairs(spec.exts or {}) do - if not extmatch or extmatch == ext:lower() then - table.insert(knownexts, ext) - end - end - end - table.sort(knownexts) - return knownexts -end - -function ide:DoWhenIdle(func) table.insert(self.onidle, func) end - -function ide:FindTopMenu(item) - local index = self:GetMenuBar():FindMenu((TR)(item)) - return self:GetMenuBar():GetMenu(index), index -end -function ide:FindMenuItem(itemid, menu) - local item, imenu = self:GetMenuBar():FindItem(itemid, menu) - if menu and not item then item = menu:FindItem(itemid) end - if not item then return end - menu = menu or imenu - - for pos = 0, menu:GetMenuItemCount()-1 do - if menu:FindItemByPosition(pos):GetId() == itemid then - return item, menu, pos - end - end - return -end -function ide:AttachMenu(...) - -- AttachMenu([targetmenu,] id, submenu) - -- `targetmenu` is only needed for menus not attached to the main menubar - local menu, id, submenu = ... - if select('#', ...) == 2 then menu, id, submenu = nil, ... end - local item, menu, pos = self:FindMenuItem(id, menu) - if not item then return end - - local menuitem = wx.wxMenuItem(menu, id, item:GetItemLabel(), item:GetHelp(), wx.wxITEM_NORMAL, submenu) - menu:Destroy(item) - return menu:Insert(pos, menuitem), pos -end -function ide:CloneMenu(menu) - if not menu then return end - local newmenu = wx.wxMenu() - local node = menu:GetMenuItems():GetFirst() - while node do - local item = node:GetData():DynamicCast("wxMenuItem") - newmenu:Append(item:GetId(), item:GetItemLabel(), item:GetHelp(), item:GetKind()) - node = node:GetNext() - end - return newmenu -end - -function ide:FindDocument(path) - local fileName = wx.wxFileName(path) - for _, doc in pairs(self:GetDocuments()) do - if doc.filePath and fileName:SameAs(wx.wxFileName(doc.filePath)) then - return doc - end - end - return -end -function ide:FindDocumentsByPartialPath(path) - local seps = "[\\/]" - -- add trailing path separator to make sure full directory match - if not path:find(seps.."$") then path = path .. GetPathSeparator() end - local pattern = "^"..q(path):gsub(seps, seps) - local lpattern = pattern:lower() - - local docs = {} - for _, doc in pairs(self:GetDocuments()) do - if doc.filePath - and (doc.filePath:find(pattern) - or iscaseinsensitive and doc.filePath:lower():find(lpattern)) then - table.insert(docs, doc) - end - end - return docs -end -function ide:GetInterpreter() return self.interpreter end -function ide:GetInterpreters() return self.interpreters end -function ide:GetConfig() return self.config end -function ide:GetOutput() return self.frame.bottomnotebook.errorlog end -function ide:GetConsole() return self.frame.bottomnotebook.shellbox end -function ide:GetEditorNotebook() return self.frame.notebook end -function ide:GetOutputNotebook() return self.frame.bottomnotebook end -function ide:GetOutline() return self.outline end -function ide:GetProjectNotebook() return self.frame.projnotebook end -function ide:GetProject() return FileTreeGetDir() end -function ide:GetProjectStartFile() - local projectdir = FileTreeGetDir() - local startfile = self.filetree.settings.startfile[projectdir] - return MergeFullPath(projectdir, startfile), startfile -end -function ide:GetLaunchedProcess() return self.debugger and self.debugger.pid end -function ide:GetProjectTree() return self.filetree.projtreeCtrl end -function ide:GetOutlineTree() return self.outline.outlineCtrl end -function ide:GetWatch() return self.debugger and self.debugger.watchCtrl end -function ide:GetStack() return self.debugger and self.debugger.stackCtrl end - -local statusreset -function ide:SetStatusFor(text, interval, field) - field = field or 0 - interval = interval or 2 - local statusbar = self:GetStatusBar() - if not ide.timers.status then - ide.timers.status = wx.wxTimer(statusbar) - statusbar:Connect(wx.wxEVT_TIMER, function(event) if statusreset then statusreset() end end) - end - statusreset = function() - if statusbar:GetStatusText(field) == text then statusbar:SetStatusText("", field) end - end - ide.timers.status:Start(interval*1000, wx.wxTIMER_ONE_SHOT) - statusbar:SetStatusText(text, field) -end -function ide:SetStatus(text, field) self:GetStatusBar():SetStatusText(text, field or 0) end -function ide:GetStatus(field) return self:GetStatusBar():GetStatusText(field or 0) end -function ide:PushStatus(text, field) self:GetStatusBar():PushStatusText(text, field or 0) end -function ide:PopStatus(field) self:GetStatusBar():PopStatusText(field or 0) end -function ide:Yield() wx.wxYield() end -function ide:CreateBareEditor() return CreateEditor(true) end - -local rawMethods = {"AddTextDyn", "InsertTextDyn", "AppendTextDyn", "SetTextDyn", - "GetTextDyn", "GetLineDyn", "GetSelectedTextDyn", "GetTextRangeDyn"} -local useraw = nil - -function ide:CreateStyledTextCtrl(...) - local editor = wxstc.wxStyledTextCtrl(...) - if not editor then return end - - if useraw == nil then - useraw = true - for _, m in ipairs(rawMethods) do - if not pcall(function() return editor[m:gsub("Dyn", "Raw")] end) then useraw = false; break end - end - end - - -- map all `GetTextDyn` to `GetText` or `GetTextRaw` if `*Raw` methods are present - editor.useraw = useraw - for _, m in ipairs(rawMethods) do - -- some `*Raw` methods return `nil` instead of `""` as their "normal" calls do - -- (for example, `GetLineRaw` and `GetTextRangeRaw` for parameters outside of text) - local def = m:find("^Get") and "" or nil - editor[m] = function(...) return editor[m:gsub("Dyn", useraw and "Raw" or "")](...) or def end - end - - local suffix = "\1\0" - function editor:CopyDyn() - if not self.useraw then return self:Copy() end - -- check if selected fragment is a valid UTF-8 sequence - local text = self:GetSelectedTextRaw() - if text == "" or wx.wxString.FromUTF8(text) ~= "" then return self:Copy() end - local tdo = wx.wxTextDataObject() - -- append suffix as wxwidgets (3.1+ on Windows) truncate last char for odd-length strings - local workaround = ide.osname == "Windows" and (#text % 2 > 0) and suffix or "" - tdo:SetData(wx.wxDataFormat(wx.wxDF_TEXT), text..workaround) - local clip = wx.wxClipboard.Get() - clip:Open() - clip:SetData(tdo) - clip:Close() - end - - function editor:PasteDyn() - if not self.useraw then return self:Paste() end - local tdo = wx.wxTextDataObject() - local clip = wx.wxClipboard.Get() - clip:Open() - clip:GetData(tdo) - clip:Close() - local ok, text = tdo:GetDataHere(wx.wxDataFormat(wx.wxDF_TEXT)) - -- check if the fragment being pasted is a valid UTF-8 sequence - if not ok or text == "" or wx.wxString.FromUTF8(text) ~= "" then return self:Paste() end - if ide.osname == "Windows" then text = text:gsub(suffix.."+$","") end - self:AddTextRaw(text) - self:GotoPos(self:GetCurrentPos()) - end - - function editor:GotoPosEnforcePolicy(pos) - self:GotoPos(pos) - self:EnsureVisibleEnforcePolicy(self:LineFromPosition(pos)) - end - - function editor:CanFold() - local foldable = false - for m = 0, ide.MAXMARGIN do - if editor:GetMarginWidth(m) > 0 - and editor:GetMarginMask(m) == wxstc.wxSTC_MASK_FOLDERS then - foldable = true - end - end - return foldable - end - - -- circle through "fold all" => "hide base lines" => "unfold all" - function editor:FoldSome() - editor:Colourise(0, -1) -- update doc's folding info - local foldall = false -- at least on header unfolded => fold all - local hidebase = false -- at least one base is visible => hide all - local lines = editor:GetLineCount() - - for ln = 0, lines-1 do - local foldRaw = editor:GetFoldLevel(ln) - local foldLvl = foldRaw % 4096 - local foldHdr = (math.floor(foldRaw / 8192) % 2) == 1 - - -- at least one header is expanded - foldall = foldall or (foldHdr and editor:GetFoldExpanded(ln)) - - -- at least one base can be hidden - hidebase = hidebase or ( - not foldHdr - and ln > 1 -- first line can't be hidden, so ignore it - and foldLvl == wxstc.wxSTC_FOLDLEVELBASE - and bit.band(foldRaw, wxstc.wxSTC_FOLDLEVELWHITEFLAG) == 0 - and editor:GetLineVisible(ln)) - end - - -- shows lines; this doesn't change fold status for folded lines - if not foldall and not hidebase then editor:ShowLines(0, lines-1) end - - for ln = 0, lines-1 do - local foldRaw = editor:GetFoldLevel(ln) - local foldLvl = foldRaw % 4096 - local foldHdr = (math.floor(foldRaw / 8192) % 2) == 1 - - if foldall then - if foldHdr and editor:GetFoldExpanded(ln) then - editor:ToggleFold(ln) - end - elseif hidebase then - if not foldHdr and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then - editor:HideLines(ln, ln) - end - else -- unfold all - if foldHdr and not editor:GetFoldExpanded(ln) then - editor:ToggleFold(ln) - end - end - end - editor:EnsureCaretVisible() - end - - local function getMarginWidth(editor) - local width = 0 - for m = 0, ide.MAXMARGIN do width = width + editor:GetMarginWidth(m) end - return width - end - - function editor:ShowPosEnforcePolicy(pos) - local line = self:LineFromPosition(pos) - self:EnsureVisibleEnforcePolicy(line) - -- skip the rest if line wrapping is on - if editor:GetWrapMode() ~= wxstc.wxSTC_WRAP_NONE then return end - local xwidth = self:GetClientSize():GetWidth() - getMarginWidth(self) - local xoffset = self:GetTextExtent(self:GetLineDyn(line):sub(1, pos-self:PositionFromLine(line)+1)) - self:SetXOffset(xoffset > xwidth and xoffset-xwidth or 0) - end - - function editor:ClearAny() - local length = self:GetLength() - local selections = ide.wxver >= "2.9.5" and self:GetSelections() or 1 - self:Clear() -- remove selected fragments - - -- check if the modification has failed, which may happen - -- if there is "invisible" text in the selected fragment. - -- if there is only one selection, then delete manually. - if length == self:GetLength() and selections == 1 then - self:SetTargetStart(self:GetSelectionStart()) - self:SetTargetEnd(self:GetSelectionEnd()) - self:ReplaceTarget("") - end - end - - function editor:MarkerGetAll(mask, from, to) - mask = mask or 2^24-1 - local markers = {} - local line = editor:MarkerNext(from or 0, mask) - while line > -1 do - table.insert(markers, {line, editor:MarkerGet(line)}) - if to and line > to then break end - line = editor:MarkerNext(line + 1, mask) - end - return markers - end - - editor:Connect(wx.wxEVT_KEY_DOWN, - function (event) - local keycode = event:GetKeyCode() - local mod = event:GetModifiers() - if (keycode == wx.WXK_DELETE and mod == wx.wxMOD_SHIFT) - or (keycode == wx.WXK_INSERT and mod == wx.wxMOD_CONTROL) - or (keycode == wx.WXK_INSERT and mod == wx.wxMOD_SHIFT) then - local id = keycode == wx.WXK_DELETE and ID.CUT or mod == wx.wxMOD_SHIFT and ID.PASTE or ID.COPY - ide.frame:AddPendingEvent(wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, id)) - elseif keycode == wx.WXK_CAPITAL and mod == wx.wxMOD_CONTROL then - -- ignore Ctrl+CapsLock - else - event:Skip() - end - end) - return editor -end - -function ide:LoadFile(...) return LoadFile(...) end - -function ide:CopyToClipboard(text) - if wx.wxClipboard:Get():Open() then - wx.wxClipboard:Get():SetData(wx.wxTextDataObject(text)) - wx.wxClipboard:Get():Close() - return true - end - return false -end - -function ide:GetSetting(path, setting) - local settings = self.settings - local curpath = settings:GetPath() - settings:SetPath(path) - local ok, value = settings:Read(setting) - settings:SetPath(curpath) - return ok and value or nil -end - -function ide:RemoveMenuItem(id, menu) - local _, menu, pos = self:FindMenuItem(id, menu) - if menu then - self:GetMainFrame():Disconnect(id, wx.wxID_ANY, wx.wxEVT_COMMAND_MENU_SELECTED) - self:GetMainFrame():Disconnect(id, wx.wxID_ANY, wx.wxEVT_UPDATE_UI) - menu:Disconnect(id, wx.wxID_ANY, wx.wxEVT_COMMAND_MENU_SELECTED) - menu:Disconnect(id, wx.wxID_ANY, wx.wxEVT_UPDATE_UI) - menu:Remove(id) - - local positem = menu:FindItemByPosition(pos) - if (not positem or positem:GetKind() == wx.wxITEM_SEPARATOR) - and pos > 0 - and (menu:FindItemByPosition(pos-1):GetKind() == wx.wxITEM_SEPARATOR) then - menu:Destroy(menu:FindItemByPosition(pos-1)) - end - return true - end - return false -end - -function ide:ExecuteCommand(cmd, wdir, callback, endcallback) - local proc = wx.wxProcess(self:GetOutput()) - proc:Redirect() - - local cwd - if (wdir and #wdir > 0) then -- ignore empty directory - cwd = wx.wxFileName.GetCwd() - cwd = wx.wxFileName.SetCwd(wdir) and cwd - end - - local pid = wx.wxExecute(cmd, wx.wxEXEC_ASYNC, proc) - pid = pid ~= -1 and pid ~= 0 and pid or nil - if cwd then wx.wxFileName.SetCwd(cwd) end -- restore workdir - if not pid then return pid, wx.wxSysErrorMsg() end - - OutputSetCallbacks(pid, proc, callback or function() end, endcallback) - return pid -end - -function ide:CreateImageList(group, ...) - local _ = wx.wxLogNull() -- disable error reporting in popup - local size = wx.wxSize(16,16) - local imglist = wx.wxImageList(16,16) - for i = 1, select('#', ...) do - local icon, file = self:GetBitmap(select(i, ...), group, size) - if imglist:Add(icon) == -1 then - DisplayOutputLn(("Failed to add image '%s' to the image list.") - :format(file or select(i, ...))) - end - end - return imglist -end - -local tintdef = 100 -local function iconFilter(bitmap, tint) - if type(tint) == 'function' then return tint(bitmap) end - if type(tint) ~= 'table' or #tint ~= 3 then return bitmap end - - local tr, tg, tb = tint[1]/255, tint[2]/255, tint[3]/255 - local pi = 0.299*tr + 0.587*tg + 0.114*tb -- pixel intensity - local perc = (tint[0] or tintdef)/tintdef - tr, tg, tb = tr*perc, tg*perc, tb*perc - - local img = bitmap:ConvertToImage() - for x = 0, img:GetWidth()-1 do - for y = 0, img:GetHeight()-1 do - if not img:IsTransparent(x, y) then - local r, g, b = img:GetRed(x, y)/255, img:GetGreen(x, y)/255, img:GetBlue(x, y)/255 - local gs = (r + g + b) / 3 - local weight = 1-4*(gs-0.5)*(gs-0.5) - r = math.max(0, math.min(255, math.floor(255 * (gs + (tr-pi) * weight)))) - g = math.max(0, math.min(255, math.floor(255 * (gs + (tg-pi) * weight)))) - b = math.max(0, math.min(255, math.floor(255 * (gs + (tb-pi) * weight)))) - img:SetRGB(x, y, r, g, b) - end - end - end - return wx.wxBitmap(img) -end - -local icons = {} -- icon cache to avoid reloading the same icons -function ide:GetBitmap(id, client, size) - local im = self.config.imagemap - local width = size:GetWidth() - local key = width.."/"..id - local keyclient = key.."-"..client - local mapped = im[keyclient] or im[id.."-"..client] or im[key] or im[id] - -- mapped may be a file name/path or wxImage object; take that into account - if type(im[id.."-"..client]) == 'string' then keyclient = width.."/"..im[id.."-"..client] - elseif type(im[keyclient]) == 'string' then keyclient = im[keyclient] - elseif type(im[id]) == 'string' then - id = im[id] - key = width.."/"..id - keyclient = key.."-"..client - end - - local fileClient = self:GetAppName() .. "/res/" .. keyclient .. ".png" - local fileKey = self:GetAppName() .. "/res/" .. key .. ".png" - local isImage = type(mapped) == 'userdata' and mapped:GetClassInfo():GetClassName() == 'wxImage' - local file - if mapped and (isImage or wx.wxFileName(mapped):FileExists()) then file = mapped - elseif wx.wxFileName(fileClient):FileExists() then file = fileClient - elseif wx.wxFileName(fileKey):FileExists() then file = fileKey - else return wx.wxArtProvider.GetBitmap(id, client, size) end - local icon = icons[file] or iconFilter(wx.wxBitmap(file), self.config.imagetint) - icons[file] = icon - return icon, file -end - -function ide:AddPackage(name, package) - self.packages[name] = setmetatable(package, self.proto.Plugin) - self.packages[name].fname = name - return self.packages[name] -end -function ide:RemovePackage(name) self.packages[name] = nil end - -function ide:AddWatch(watch, value) - local mgr = self.frame.uimgr - local pane = mgr:GetPane("watchpanel") - if (pane:IsOk() and not pane:IsShown()) then - pane:Show() - mgr:Update() - end - - local watchCtrl = self.debugger.watchCtrl - if not watchCtrl then return end - - local root = watchCtrl:GetRootItem() - if not root or not root:IsOk() then return end - - local item = watchCtrl:GetFirstChild(root) - while true do - if not item:IsOk() then break end - if watchCtrl:GetItemExpression(item) == watch then - if value then watchCtrl:SetItemText(item, watch .. ' = ' .. tostring(value)) end - return item - end - item = watchCtrl:GetNextSibling(item) - end - - item = watchCtrl:AppendItem(root, watch, 1) - watchCtrl:SetItemExpression(item, watch, value) - return item -end - -function ide:AddInterpreter(name, interpreter) - self.interpreters[name] = setmetatable(interpreter, self.proto.Interpreter) - ProjectUpdateInterpreters() -end -function ide:RemoveInterpreter(name) - self.interpreters[name] = nil - ProjectUpdateInterpreters() -end - -function ide:AddSpec(name, spec) - self.specs[name] = spec - UpdateSpecs() -end -function ide:RemoveSpec(name) self.specs[name] = nil end - -function ide:AddAPI(type, name, api) - self.apis[type] = self.apis[type] or {} - self.apis[type][name] = api -end -function ide:RemoveAPI(type, name) self.apis[type][name] = nil end - -function ide:AddConsoleAlias(alias, table) return ShellSetAlias(alias, table) end -function ide:RemoveConsoleAlias(alias) return ShellSetAlias(alias, nil) end - -function ide:AddMarker(...) return StylesAddMarker(...) end -function ide:GetMarker(marker) return StylesGetMarker(marker) end -function ide:RemoveMarker(marker) StylesRemoveMarker(marker) end - -local indicators = {} -function ide:AddIndicator(indic, num) - num = num or indicators[indic] - if not num then -- new indicator; find the smallest available number - local nums = {} - for _, indicator in pairs(indicators) do - if indicator >= wxstc.wxSTC_INDIC_CONTAINER then - nums[indicator-wxstc.wxSTC_INDIC_CONTAINER+1] = true - end - end - num = #nums + wxstc.wxSTC_INDIC_CONTAINER - if num > wxstc.wxSTC_INDIC_MAX then return end - end - indicators[indic] = num - return num -end -function ide:GetIndicator(indic) return indicators[indic] end -function ide:GetIndicators() return indicators end -function ide:RemoveIndicator(indic) indicators[indic] = nil end - --- this provides a simple stack for saving/restoring current configuration -local configcache = {} -function ide:AddConfig(name, files) - if not name or configcache[name] then return end -- don't overwrite existing slots - if type(files) ~= "table" then files = {files} end -- allow to pass one value - configcache[name] = { - config = require('mobdebug').dump(self.config, {nocode = true}), - configmeta = getmetatable(self.config), - packages = {}, - } - -- build a list of existing packages - local packages = {} - for package in pairs(self.packages) do packages[package] = true end - -- load config file(s) - for _, file in pairs(files) do LoadLuaConfig(MergeFullPath(name, file)) end - -- register newly added packages (if any) - for package in pairs(self.packages) do - if not packages[package] then -- this is a newly added package - PackageEventHandleOne(package, "onRegister") - configcache[name].packages[package] = true - end - end - ReApplySpecAndStyles() -- apply current config to the UI -end -function ide:RemoveConfig(name) - if not name or not configcache[name] then return end - -- unregister cached packages - for package in pairs(configcache[name].packages) do PackageUnRegister(package) end - -- load original config - local ok, res = LoadSafe(configcache[name].config) - if ok then - self.config = res - if configcache[name].configmeta then setmetatable(self.config, configcache[name].configmeta) end - else - DisplayOutputLn(("Error while restoring configuration: '%s'."):format(res)) - end - configcache[name] = nil -- clear the slot after use - ReApplySpecAndStyles() -- apply current config to the UI -end - -local panels = {} -function ide:AddPanel(ctrl, panel, name, conf) - local width, height = 360, 200 - local notebook = wxaui.wxAuiNotebook(self.frame, wx.wxID_ANY, - wx.wxDefaultPosition, wx.wxDefaultSize, - wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER) - notebook:AddPage(ctrl, name, true) - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, - function() PaneFloatToggle(notebook) end) - notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, - function(event) event:Veto() end) - - local mgr = self.frame.uimgr - mgr:AddPane(notebook, wxaui.wxAuiPaneInfo(): - Name(panel):Float():CaptionVisible(false):PaneBorder(false): - MinSize(width/2,height/2): - BestSize(width,height):FloatingSize(width,height): - PinButton(true):Hide()) - if type(conf) == "function" then conf(mgr:GetPane(panel)) end - mgr.defaultPerspective = mgr:SavePerspective() -- resave default perspective - - panels[name] = {ctrl, panel, name, conf} - return mgr:GetPane(panel), notebook -end - -function ide:RemovePanel(panel) - local mgr = self.frame.uimgr - local pane = mgr:GetPane(panel) - if pane:IsOk() then - local win = pane.window - mgr:DetachPane(win) - win:Destroy() - mgr:Update() - end -end - -function ide:AddPanelDocked(notebook, ctrl, panel, name, conf, activate) - notebook:AddPage(ctrl, name, activate ~= false) - panels[name] = {ctrl, panel, name, conf} - return notebook -end -function ide:IsPanelDocked(panel) - local layout = self:GetSetting("/view", "uimgrlayout") - return layout and not layout:find(panel) -end - -function ide:IsValidCtrl(ctrl) - return ctrl and pcall(function() ctrl:GetId() end) -end - -function ide:IsValidProperty(ctrl, prop) - return ide:IsValidCtrl(ctrl) and pcall(function() return ctrl[prop] end) -end - -function ide:IsWindowShown(win) - while win do - if not win:IsShown() then return false end - win = win:GetParent() - end - return true -end - -function ide:RestorePanelByLabel(name) - if not panels[name] then return end - return self:AddPanel(unpack(panels[name])) -end - -function ide:AddTool(name, command, updateui) - return ToolsAddTool(name, command, updateui) -end - -function ide:RemoveTool(name) - return ToolsRemoveTool(name) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/print.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/print.lua deleted file mode 100644 index 9b93dcd..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/print.lua +++ /dev/null @@ -1,195 +0,0 @@ --- Copyright 2015 Paul Kulchenko, ZeroBrane LLC ---------------------------------------------------------- - -local frame = ide:GetMainFrame() -local margin = {top = 10, left = 10, bottom = 10, right = 10} -local function printScaling(dc, printOut) - local pageSizeMM_x, pageSizeMM_y = printOut:GetPageSizeMM() - - local ppiScr_x, ppiScr_y = printOut:GetPPIScreen() - local ppiPrn_x, ppiPrn_y = printOut:GetPPIPrinter() - - local ppi_scale_x = ppiPrn_x/ppiScr_x - local ppi_scale_y = ppiPrn_y/ppiScr_y - - -- get the size of DC in pixels and the number of pixels in the page - local dcSize_x, dcSize_y = dc:GetSize() - local pagePixSize_x, pagePixSize_y = printOut:GetPageSizePixels() - - local dc_pagepix_scale_x = dcSize_x/pagePixSize_x - local dc_pagepix_scale_y = dcSize_y/pagePixSize_y - - local dc_scale_x = ppi_scale_x * dc_pagepix_scale_x - local dc_scale_y = ppi_scale_y * dc_pagepix_scale_y - - -- calculate the pixels / mm (25.4 mm = 1 inch) - local ppmm_x = ppiScr_x / 25.4 - local ppmm_y = ppiScr_y / 25.4 - - -- adjust the page size for the pixels / mm scaling factor - local page_x = math.floor(pageSizeMM_x * ppmm_x) - local page_y = math.floor(pageSizeMM_y * ppmm_y) - local pageRect = wx.wxRect(0, 0, page_x, page_y) - - -- get margins informations and convert to printer pixels - local top = math.floor(margin.top * ppmm_y) - local bottom = math.floor(margin.bottom * ppmm_y) - local left = math.floor(margin.left * ppmm_x) - local right = math.floor(margin.right * ppmm_x) - - dc:SetUserScale(dc_scale_x, dc_scale_y) - - local printRect = wx.wxRect(left, top, page_x-(left+right), page_y-(top+bottom)) - return printRect, pageRect -end - -local function connectPrintEvents(printer, printOut) - local editor = ide:GetEditorWithFocus() - local cfg = ide.config.print - local pages - - function printOut:OnPrintPage(pageNum) - local dc = self:GetDC() - local printRect, pageRect = printScaling(dc, printOut) - - -- print to an area smaller by the height of the header/footer - dc:SetFont(editor:GetFont()) - local _, headerHeight = dc:GetTextExtent("qH") - local textRect = wx.wxRect(printRect) - if cfg.header then - textRect:SetY(textRect:GetY() + headerHeight*1.5) - textRect:SetHeight(textRect:GetHeight() - headerHeight*1.5) - end - if cfg.footer then - textRect:SetHeight(textRect:GetHeight() - headerHeight*1.5) - end - - local selection = printer:GetPrintDialogData():GetSelection() - local spos = selection and editor:GetSelectionStart() or 1 - local epos = selection and editor:GetSelectionEnd() or editor:GetLength() - if pageNum == nil then - pages = {} - ide:PushStatus("") - printOut.startTime = wx.wxNow() - local pos = spos - while pos < epos do - table.insert(pages, pos) - pos = editor:FormatRange(false, pos, epos, dc, dc, textRect, pageRect) - ide:PopStatus() - ide:PushStatus(TR("%s%% formatted..."):format(math.floor((pos-spos)*100.0/(epos-spos)))) - end - if #pages == 0 then pages = {0} end - ide:PopStatus() - else - ide:SetStatusFor(TR("Formatting page %d..."):format(pageNum)) - editor:FormatRange(true, pages[pageNum], epos, dc, dc, textRect, pageRect) - - local c = wx.wxColour(127, 127, 127) - dc:SetPen(wx.wxPen(c, 1, wx.wxSOLID)) - dc:SetTextForeground(c) - - local doc = ide:GetDocument(editor) - local format = "([^\t]*)\t?([^\t]*)\t?([^\t]*)" - local placeholders = { - D = printOut.startTime, - p = pageNum, - P = #pages, - S = doc and doc:GetFileName() or "", - } - dc:SetFont(editor:GetFont()) - if cfg.header then - local left, center, right = ExpandPlaceholders(cfg.header, placeholders):match(format) - dc:DrawText(left, printRect.X, printRect.Y) - dc:DrawText(center, printRect.Left + (printRect.Left + printRect.Width - dc:GetTextExtentSize(center).Width)/2, printRect.Y) - dc:DrawText(right, printRect.Left + printRect.Width - dc:GetTextExtentSize(right).Width, printRect.Y) - dc:DrawLine(printRect.X, printRect.Y + headerHeight, printRect.Left + printRect.Width, printRect.Y + headerHeight) - end - if cfg.footer then - local footerY = printRect.Y + printRect.Height - headerHeight - local left, center, right = ExpandPlaceholders(cfg.footer, placeholders):match(format) - dc:DrawText(left, printRect.X, footerY) - dc:DrawText(center, printRect.Left + (printRect.Left + printRect.Width - dc:GetTextExtentSize(center).Width)/2, footerY) - dc:DrawText(right, printRect.Left + printRect.Width - dc:GetTextExtentSize(right).Width, footerY) - dc:DrawLine(printRect.X, footerY, printRect.Left + printRect.Width, footerY) - end - end - return true - end - function printOut:HasPage(pageNum) return pages[pageNum] ~= nil end - function printOut:GetPageInfo() - -- on Linux `GetPageInfo` is called before the canvas is initialized, which prevents - -- proper calculation of the number of pages (wx2.9.5). - -- Return defaults here as it's going to be called once more in the right place. - if ide.osname == "Unix" and not pages then return 1, 9999, 1, 9999 end - local printDD = printer:GetPrintDialogData() - -- due to wxwidgets bug (http://trac.wxwidgets.org/ticket/17200), if `to` page is not set explicitly, - -- only one page is being printed when `selection` option is selected in the print dialog. - if printDD:GetSelection() then printDD:SetToPage(#pages) end -- set the page as a workaround - local tofrom = not printDD:GetSelection() and not printDD:GetAllPages() - return 1, #pages, tofrom and printDD:GetFromPage() or 1, tofrom and printDD:GetToPage() or #pages - end - function printOut:OnPreparePrinting() self:OnPrintPage() end -end - -frame:Connect(ID_PAGESETUP, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local pageSetupDD = wx.wxPageSetupDialogData() - pageSetupDD.MarginTopLeft = wx.wxPoint(margin.left, margin.top) - pageSetupDD.MarginBottomRight = wx.wxPoint(margin.right, margin.bottom) - pageSetupDD:EnableOrientation(false) - pageSetupDD:EnablePaper(false) - - local pageSetupDialog = wx.wxPageSetupDialog(frame, pageSetupDD) - pageSetupDialog:ShowModal() - pageSetupDD = pageSetupDialog:GetPageSetupDialogData() - margin.top, margin.left = pageSetupDD.MarginTopLeft.y, pageSetupDD.MarginTopLeft.x - margin.bottom, margin.right = pageSetupDD.MarginBottomRight.y, pageSetupDD.MarginBottomRight.x - end) - -frame:Connect(ID_PRINT, wx.wxEVT_COMMAND_MENU_SELECTED, - function (event) - local cfg = ide.config.print - local editor = ide:GetEditorWithFocus() - editor:SetPrintMagnification(cfg.magnification) - editor:SetPrintColourMode(cfg.colourmode) - editor:SetPrintWrapMode(cfg.wrapmode) - - -- only enable selection if there is something selected in the editor (ignore multiple selections) - local printDD = wx.wxPrintDialogData() - printDD:EnableSelection(editor:GetSelectionStart() ~= editor:GetSelectionEnd()) - - local printer = wx.wxPrinter(printDD) - local luaPrintout = wx.wxLuaPrintout() - connectPrintEvents(printer, luaPrintout) - - -- save and hide indicators - local indics = {} - for _, num in pairs(ide:GetIndicators()) do - indics[num] = editor:IndicatorGetStyle(num) - editor:IndicatorSetStyle(num, wxstc.wxSTC_INDIC_HIDDEN) - end - -- bold keywords - local keywords = {} - for _, num in ipairs(ide:IsValidProperty(editor, 'spec') and editor.spec.lexerstyleconvert and editor.spec.lexerstyleconvert.keywords0 or {}) do - keywords[num] = editor:StyleGetBold(num) - editor:StyleSetBold(num, true) - end - local ok = printer:Print(frame, luaPrintout, true) - -- restore indicators - for n, style in pairs(indics) do editor:IndicatorSetStyle(n, style) end - for n, style in pairs(keywords) do editor:StyleSetBold(n, style) end - if not ok and printer:GetLastError() == wx.wxPRINTER_ERROR then - ReportError("There was a problem while printing.\nCheck if your current printer is set correctly.") - end - end) - -frame:Connect(ID_PRINT, wx.wxEVT_UPDATE_UI, function(event) event:Enable(ide:GetEditorWithFocus() ~= nil) end) - -local _, menu, epos = ide:FindMenuItem(ID.EXIT) --- disable printing on Unix/Linux as it generates incorrect layout (wx2.9.5, wx3.1) -if ide.osname ~= "Unix" and menu and epos then - -- insert Print-repated menu items (going in the opposite order) - menu:Insert(epos-1, ID_PAGESETUP, TR("Page Setup..."), "") - menu:Insert(epos-1, ID_PRINT, TR("&Print..."), TR("Print the current document")) - menu:InsertSeparator(epos-1) -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/proto.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/proto.lua deleted file mode 100644 index fd24f50..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/proto.lua +++ /dev/null @@ -1,68 +0,0 @@ --- Copyright 2013-15 Paul Kulchenko, ZeroBrane LLC ---------------------------------------------------------- - -local q = EscapeMagic -local modpref = ide.MODPREF - -ide.proto.Document = {__index = { - GetFileName = function(self) return self.fileName end, - GetFilePath = function(self) return self.filePath end, - GetFileExt = function(self) return GetFileExt(self.fileName) end, - GetModTime = function(self) return self.modTime end, - GetEditor = function(self) return self.editor end, - GetTabIndex = function(self) return self.index end, - IsModified = function(self) return self.isModified end, - IsNew = function(self) return self.filePath == nil end, - SetModified = function(self, modified) - self.isModified = modified - self:SetTabText() - end, - SetTabText = function(self, text) - ide:GetEditorNotebook():SetPageText(self.index, - (self.isModified and modpref or '')..(text or self:GetTabText())) - end, - GetTabText = function(self) - if self.index == nil then return self.fileName end - return ide:GetEditorNotebook():GetPageText(self.index):gsub("^"..q(modpref), "") - end, - SetActive = function(self) SetEditorSelection(self.index) end, - Save = function(self) return SaveFile(self.editor, self.filePath) end, - Close = function(self) return ClosePage(self.index) end, - CloseAll = function(self) return CloseAllPagesExcept(-1) end, - CloseAllExcept = function(self) return CloseAllPagesExcept(self.index) end, -}} - -ide.proto.Plugin = {__index = { - GetName = function(self) return self.name end, - GetFileName = function(self) return self.fname end, - GetFilePath = function(self) return MergeFullPath(GetPathWithSep(ide.editorFilename), self.fpath) end, - GetConfig = function(self) return ide.config[self.fname] or {} end, - GetSettings = function(self) return SettingsRestorePackage(self.fname) end, - SetSettings = function(self, settings, opts) SettingsSavePackage(self.fname, settings, opts) end, -}} - -ide.proto.Interpreter = {__index = { - GetName = function(self) return self.name end, - GetFileName = function(self) return self.fname end, - GetExePath = function(self, ...) return self:fexepath(...) end, - GetAPI = function(self) return self.api end, - fprojdir = function(self,wfilename) - return wfilename:GetPath(wx.wxPATH_GET_VOLUME) - end, - fworkdir = function (self,wfilename) - local proj = ide:GetProject() - return proj and proj:gsub("[\\/]$","") or wfilename:GetPath(wx.wxPATH_GET_VOLUME) - end, -}} - -ide.proto.Debugger = {__index = { - IsRunning = function(self) return self.running end, - IsConnected = function(self) return self.server end, - GetHostName = function(self) return self.hostname end, - GetPortNumber = function(self) return self.portnumber end, -}} - -ide.proto.ID = { - __index = function(_, id) return _G['ID_'..id] end, - __call = function(_, id) return IDgen(id) end, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/settings.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/settings.lua deleted file mode 100644 index 5f776b6..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/settings.lua +++ /dev/null @@ -1,593 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local layoutlabel = { - UIMANAGER = "uimgrlayout", - NOTEBOOK = "nblayout", - NOTEBOOKOUTPUT = "nbbtmlayout", - NOTEBOOKPROJECT = "nbprojlayout", - DOCKNOTEBOOK = "nbdocklayout", - DOCKNOTEBOOKOUTPUT = "nbbtmdocklayout", - DOCKNOTEBOOKPROJECT = "nbprojdocklayout", - STATUSBAR = "statusbar", -} - --- ---------------------------------------------------------------------------- --- Initialize the wxConfig for loading/saving the preferences - -local ini = ide.config.ini --- if ini path is relative and includes a directory name, make it relative to the IDE location -ini = ini and (not wx.wxIsAbsolutePath(ini) and wx.wxFileName(ini):GetDirCount() > 0 - and MergeFullPath(GetPathWithSep(ide.editorFilename), ini) or ini) --- check that the ini file doesn't point to a directory -if ini and (wx.wxFileName(ini):IsDir() or wx.wxIsAbsolutePath(ini) and wx.wxDirExists(ini)) then - print(("Can't use 'ini' configuration setting '%s' that points to a directory instead of a file; ignored.") - :format(ini)) - ini = nil -end --- check that the directory is writable -if ini and wx.wxIsAbsolutePath(ini) and not wx.wxFileName(ini):IsDirWritable() then - print(("Can't use 'ini' configuration setting '%s' that points to a non-writable directory; ignored.") - :format(ini)) - ini = nil -end - -local settings = wx.wxFileConfig(GetIDEString("settingsapp"), GetIDEString("settingsvendor"), ini or "") -ide.settings = settings - -local function settingsReadSafe(settings,what,default) - local cr,out = settings:Read(what,default) - return cr and out or default -end - --- ---------------------------------------------------------------------------- --- wxConfig load/save preferences functions - -function SettingsRestoreFramePosition(window, windowName) - local path = settings:GetPath() - settings:SetPath("/"..windowName) - - local s = tonumber(select(2,settings:Read("s", -1))) - local x = tonumber(select(2,settings:Read("x", 0))) - local y = tonumber(select(2,settings:Read("y", 0))) - local w = tonumber(select(2,settings:Read("w", 1100))) - local h = tonumber(select(2,settings:Read("h", 700))) - - if (s ~= -1) and (s ~= 1) and (s ~= 2) then - local clientX, clientY, clientWidth, clientHeight = wx.wxClientDisplayRect() - - if x < clientX then x = clientX end - if y < clientY then y = clientY end - - if w > clientWidth then w = clientWidth end - if h > clientHeight then h = clientHeight end - - window:SetSize(x, y, w, h) - elseif s == 1 then - window:Maximize(true) - end - - settings:SetPath(path) -end - -function SettingsSaveFramePosition(window, windowName) - local path = settings:GetPath() - settings:SetPath("/"..windowName) - - local s = 0 - local w, h = window:GetSizeWH() - local x, y = window:GetPositionXY() - - if window:IsMaximized() then - s = 1 - elseif window:IsIconized() then - s = 2 - end - - settings:Write("s", s==2 and 0 or s) -- iconized maybe - but that shouldnt be saved - - if s == 0 then - settings:Write("x", x) - settings:Write("y", y) - settings:Write("w", w) - settings:Write("h", h) - end - - settings:SetPath(path) -end - ---- --- (table) SettingsRestoreFileHistory (function) --- restores a list of recently loaded documents from the settings table --- a table is returned which contains tables each with a filename key, pointing to --- the filename -function SettingsRestoreFileHistory(fntab) - local path = settings:GetPath() - local listname = "/filehistory" - settings:SetPath(listname) - - local outtab = {} - local inlist = {} - for id=1,ide.config.filehistorylength do - local couldread, name = settings:Read(tostring(id), "") - if not couldread or name == "" then break end - if not inlist[name] then - inlist[name] = true - table.insert(outtab,{filename = name}) - end - end - - if fntab then fntab(outtab) end - - settings:SetPath(path) - - return outtab -end - -function SettingsSaveFileHistory (filehistory) - local listname = "/filehistory" - local path = settings:GetPath() - settings:DeleteGroup(listname) - settings:SetPath(listname) - - for i,doc in ipairs(filehistory) do - settings:Write(tostring(i), doc.filename) - end - - settings:SetPath(path) -end - ---- --- () SettingsRestoreFileSession (function [, string section]) --- restores a list of opened files from the file settings --- calls the given function with the restored table, a list --- of tables containing tables like --- {filename = "filename", cursorpos = } -function SettingsRestoreFileSession(fntab, section) - local listname = section or "/session" - local path = settings:GetPath() - settings:SetPath(listname) - local outtab = {} - local params = {} - local ismore, key, index = settings:GetFirstEntry("", 0) - while (ismore) do - local couldread, value = settings:Read(key, "") - if tonumber(key) then - local fname,cursorpos = value:match("^(.+);(.-)$") - if (couldread and value ~= "") then - outtab[tonumber(key)] = - {filename = fname or value, cursorpos = tonumber(cursorpos) or 0} - end - else - params[key] = tonumber(value) or value - end - ismore, key, index = settings:GetNextEntry(index) - end - - if fntab then fntab(outtab, params) end - - settings:SetPath(path) - - return outtab -end - ---- --- () SettingsSaveFileSession (table opendocs, table params [, string section]) --- saves the list of currently opened documents (passed in the opendocs table) --- in the settings. -function SettingsSaveFileSession(opendocs, params, section) - local listname = section or "/session" - local path = settings:GetPath() - settings:DeleteGroup(listname) - settings:SetPath(listname) - - for i,doc in ipairs(opendocs) do - settings:Write(tostring(i), doc.filename..";"..doc.cursorpos) - end - - -- save all other parameters - for k,v in pairs(params) do settings:Write(k, v) end - - settings:SetPath(path) -end - ---- --- () SettingsRestoreProjectSession (function) -function SettingsRestoreProjectSession(fntab) - local listname = "/projectsession" - local path = settings:GetPath() - settings:SetPath(listname) - local outtab = {} - local couldread = true - local id = 1 - local name - while (couldread) do - couldread, name = settings:Read(tostring(id), "") - couldread = couldread and name ~= "" - if (couldread) then - if (wx.wxDirExists(name)) then - table.insert(outtab,name) - - local function projsession(...) ProjectConfig(name, {...}) end - SettingsRestoreFileSession(projsession, listname .. "/" .. tostring(id)) - end - id = id + 1 - end - end - - if fntab then fntab(outtab) end - - settings:SetPath(path) - - return outtab -end - ---- --- () SettingsSaveProjectSession (table projdirs) --- saves the list of currently active projects --- in the settings. -function SettingsSaveProjectSession(projdirs) - local listname = "/projectsession" - local path = settings:GetPath() - settings:DeleteGroup(listname) - settings:SetPath(listname) - - for i,dir in ipairs(projdirs) do - settings:Write(tostring(i), dir) - - local opendocs, params = ProjectConfig(dir) - if opendocs then - SettingsSaveFileSession(opendocs, params, listname .. "/" .. tostring(i)) - end - end - - settings:SetPath(path) -end - -function SettingsRestorePackage(package) - local packagename = "/package/"..package - local path = settings:GetPath() - settings:SetPath(packagename) - local outtab = {} - local ismore, key, index = settings:GetFirstEntry("", 0) - while (ismore) do - local couldread, value = settings:Read(key, "") - if couldread then - local ok, res = LoadSafe("return "..value) - if ok then outtab[key] = res - else - outtab[key] = nil - ide:Print(("Couldn't load and ignored '%s' settings for package '%s': %s") - :format(key, package, res)) - end - end - ismore, key, index = settings:GetNextEntry(index) - end - settings:SetPath(path) - return outtab -end - -local function plaindump(val, opts, done) - local keyignore = opts and opts.keyignore or {} - local final = done == nil - opts, done = opts or {}, done or {} - local t = type(val) - if t == "table" then - done[#done+1] = '{' - done[#done+1] = '' - for key, value in pairs (val) do - if not keyignore[key] then - done[#done+1] = '[' - plaindump(key, opts, done) - done[#done+1] = ']=' - plaindump(value, opts, done) - done[#done+1] = "," - end - end - done[#done] = '}' - elseif t == "string" then - done[#done+1] = ("%q"):format(val):gsub("\010","n"):gsub("\026","\\026") - elseif t == "number" then - done[#done+1] = ("%.17g"):format(val) - else - done[#done+1] = tostring(val) - end - return final and table.concat(done, '') -end - -function SettingsSavePackage(package, values, opts) - local packagename = "/package/"..package - local path = settings:GetPath() - - settings:DeleteGroup(packagename) - settings:SetPath(packagename) - for k,v in pairs(values or {}) do settings:Write(k, plaindump(v, opts)) end - settings:SetPath(path) -end - ------------------------------------ - -local function saveNotebook(nb) - local cnt = nb:GetPageCount() - - local function addTo(tab,key,value) - local out = tab[key] or {} - table.insert(out,value) - tab[key] = out - end - - local pagesX = {} - local pagesY = {} - - local str = "nblayout|" - - for i=1,cnt do - local id = nb:GetPageText(i-1) - local pg = nb:GetPage(i-1) - local x,y = pg:GetPosition():GetXY() - addTo(pagesX,x,id) - addTo(pagesY,y,id) - end - - local function sortedPages(tab) - local t = {} - for i in pairs(tab) do - table.insert(t,i) - end - table.sort(t) - return t - end - - local sortedX = sortedPages(pagesX) - local sortedY = sortedPages(pagesY) - - -- for now only support "1D" splits and prefer - -- dimension which has more, anything else - -- requires a more complex algorithm, yet to do - - local pagesUse - local sortedUse - local split - - if ( #sortedX >= #sortedY) then - pagesUse = pagesX - sortedUse = sortedX - split = "" - else - pagesUse = pagesY - sortedUse = sortedY - split = "" - end - - for _, v in ipairs(sortedUse) do - local pages = pagesUse[v] - for _, id in ipairs(pages) do - str = str..id.."|" - end - str = str..split.."|" - end - - return str -end - -local function loadNotebook(nb,str,fnIdConvert) - str = str:match("nblayout|(.+)") - if (not str) then return end - local cnt = nb:GetPageCount() - local sel = nb:GetSelection() - - -- store old pages - local currentpages, order = {}, {} - for i=1,cnt do - local id = nb:GetPageText(i-1) - local newid = fnIdConvert and fnIdConvert(id) or id - currentpages[newid] = currentpages[newid] or {} - table.insert(currentpages[newid], {page = nb:GetPage(i-1), text = id, index = i-1}) - order[i] = newid - end - - -- remove them - for i=cnt,1,-1 do nb:RemovePage(i-1) end - - -- read them and perform splits - local t = 0 - local newsel - local function finishPage(page) - if (page.index == sel) then - newsel = t - end - t = t + 1 - end - - local direction - local splits = { X = wx.wxRIGHT, Y = wx.wxBOTTOM } - for cmd in str:gmatch("([^|]+)") do - local instr = cmd:match("<(%w)>") - if (not instr) then - local id = fnIdConvert and fnIdConvert(cmd) or cmd - local pageind = next(currentpages[id] or {}) - if (pageind) then - local page = currentpages[id][pageind] - currentpages[id][pageind] = nil - - nb:AddPage(page.page, page.text) - if (direction) then nb:Split(t, direction) end - finishPage(page) - end - end - direction = instr and splits[instr] - end - - -- add anything we forgot; make sure page groups are in the order specified - for i=1,cnt do - local pagelist = currentpages[order[i]] - for _,page in pairs(pagelist) do - nb:AddPage(page.page, page.text) - finishPage(page) - end - end - - -- set the active page as it was before - if (newsel) then nb:SetSelection(newsel) end -end - -function SettingsRestoreView() - local listname = "/view" - local path = settings:GetPath() - settings:SetPath(listname) - - local frame = ide.frame - local uimgr = frame.uimgr - - local layoutcur = uimgr:SavePerspective() - local layout = settingsReadSafe(settings,layoutlabel.UIMANAGER,"") - if (layout ~= layoutcur) then - -- save the current toolbar besth and re-apply after perspective is loaded - -- bestw and besth has two separate issues: - -- (1) layout includes bestw that is only as wide as the toolbar size, - -- this leaves default background on the right side of the toolbar; - -- fix it by explicitly replacing with the screen width. - -- (2) besth may be wrong after icon size changes. - local toolbar = frame.uimgr:GetPane("toolbar") - local besth = toolbar:IsOk() and tonumber(uimgr:SavePaneInfo(toolbar):match("besth=([^;]+)")) - - -- reload the perspective if the saved one is not empty as it's different from the default - if #layout > 0 then uimgr:LoadPerspective(layout, false) end - - local screenw = frame:GetClientSize():GetWidth() - if toolbar:IsOk() and screenw > 0 then toolbar:BestSize(screenw, besth or -1) end - - -- check if debugging panes are not mentioned and float them - for _, name in pairs({"stackpanel", "watchpanel"}) do - local pane = frame.uimgr:GetPane(name) - if pane:IsOk() and not layout:find(name) then pane:Float() end - end - - -- check if the toolbar is not mentioned in the layout and show it - for _, name in pairs({"toolbar"}) do - local pane = frame.uimgr:GetPane(name) - if pane:IsOk() and not layout:find(name) then pane:Show() end - end - - -- remove captions from all panes - local panes = frame.uimgr:GetAllPanes() - for index = 0, panes:GetCount()-1 do - uimgr:GetPane(panes:Item(index).name):CaptionVisible(false) - end - end - - frame:GetStatusBar():Show(settingsReadSafe(settings,layoutlabel.STATUSBAR,true)) - - uimgr:Update() - - layoutcur = saveNotebook(ide:GetOutputNotebook()) - layout = settingsReadSafe(settings,layoutlabel.NOTEBOOKOUTPUT,layoutcur) - if (layout ~= layoutcur) then - loadNotebook(ide:GetOutputNotebook(),layout, - -- treat "Output (running)" same as "Output" - function(name) return - name:match(TR("Output")) or name:match("Output") or name end) - end - - layoutcur = saveNotebook(ide:GetProjectNotebook()) - layout = settingsReadSafe(settings,layoutlabel.NOTEBOOKPROJECT,layoutcur) - if (layout ~= layoutcur) then - loadNotebook(ide:GetProjectNotebook(),layout) - end - - -- always select Output tab - local bottomnotebook = ide:GetOutputNotebook() - local index = bottomnotebook:GetPageIndex(bottomnotebook.errorlog) - if index >= 0 then bottomnotebook:SetSelection(index) end - - layoutcur = saveNotebook(frame.notebook) - layout = settingsReadSafe(settings,layoutlabel.NOTEBOOK,layoutcur) - if (layout ~= layoutcur) then - loadNotebook(ide.frame.notebook,layout) - local openDocuments = ide.openDocuments - local nb = frame.notebook - local cnt = nb:GetPageCount() - for i=0,cnt-1 do - openDocuments[nb:GetPage(i):GetId()].index = i - end - end - - -- restore configuration for notebook pages that have been split; - -- load saved dock_size values and update current values with saved ones - -- where dock_size configuration matches - for l, m in pairs({ - [layoutlabel.DOCKNOTEBOOK] = ide:GetEditorNotebook():GetAuiManager(), - [layoutlabel.DOCKNOTEBOOKOUTPUT] = ide:GetOutputNotebook():GetAuiManager(), - [layoutlabel.DOCKNOTEBOOKPROJECT] = ide:GetProjectNotebook():GetAuiManager(), - }) do - -- ...|dock_size(5,0,0)=20|dock_size(2,1,0)=200|... - local prevlayout = settingsReadSafe(settings, l, "") - local curlayout = m:SavePerspective() - local newlayout = curlayout:gsub('(dock_size[^=]+=)(%d+)', function(t,v) - local val = prevlayout:match(EscapeMagic(t)..'(%d+)') - return t..(val or v) - end) - if newlayout ~= curlayout then m:LoadPerspective(newlayout) end - end - - local editor = GetEditor() - if editor then editor:SetFocus() end - - settings:SetPath(path) -end - -function SettingsSaveView() - local listname = "/view" - local path = settings:GetPath() - settings:DeleteGroup(listname) - settings:SetPath(listname) - - local frame = ide.frame - local uimgr = frame.uimgr - - settings:Write(layoutlabel.UIMANAGER, uimgr:SavePerspective()) - settings:Write(layoutlabel.NOTEBOOK, saveNotebook(ide:GetEditorNotebook())) - settings:Write(layoutlabel.NOTEBOOKOUTPUT, saveNotebook(ide:GetOutputNotebook())) - settings:Write(layoutlabel.NOTEBOOKPROJECT, saveNotebook(ide:GetProjectNotebook())) - settings:Write(layoutlabel.DOCKNOTEBOOK, ide:GetEditorNotebook():GetAuiManager():SavePerspective()) - settings:Write(layoutlabel.DOCKNOTEBOOKOUTPUT, ide:GetOutputNotebook():GetAuiManager():SavePerspective()) - settings:Write(layoutlabel.DOCKNOTEBOOKPROJECT, ide:GetProjectNotebook():GetAuiManager():SavePerspective()) - settings:Write(layoutlabel.STATUSBAR, frame:GetStatusBar():IsShown()) - - settings:SetPath(path) -end - -function SettingsRestoreEditorSettings() - local listname = "/editor" - local path = settings:GetPath() - settings:SetPath(listname) - - local interpreter = settingsReadSafe(settings, "interpreter", - ide.config.interpreter or ide.config.default.interpreter) - ProjectSetInterpreter(interpreter) - - settings:SetPath(path) -end - -function SettingsSaveEditorSettings() - local listname = "/editor" - local path = settings:GetPath() - settings:DeleteGroup(listname) - settings:SetPath(listname) - - settings:Write("interpreter", ide.interpreter and ide.interpreter.fname or ide.config.default.interpreter) - - settings:SetPath(path) -end - -function SettingsSaveAll() - SettingsSaveFileSession(GetOpenFiles()) - SettingsSaveEditorSettings() - SettingsSaveProjectSession(FileTreeGetProjects()) - SettingsSaveFileHistory(GetFileHistory()) - SettingsSaveView() - SettingsSaveFramePosition(ide.frame, "MainFrame") -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/shellbox.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/shellbox.lua deleted file mode 100644 index f3fd52b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/shellbox.lua +++ /dev/null @@ -1,574 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide -local unpack = table.unpack or unpack - -local bottomnotebook = ide.frame.bottomnotebook -local out = bottomnotebook.shellbox -local remotesend - -local PROMPT_MARKER = StylesGetMarker("prompt") -local PROMPT_MARKER_VALUE = 2^PROMPT_MARKER -local ERROR_MARKER = StylesGetMarker("error") -local OUTPUT_MARKER = StylesGetMarker("output") -local MESSAGE_MARKER = StylesGetMarker("message") -local ANY_MARKER_VALUE = 2^25-1 -- marker numbers 0 to 24 have no pre-defined function - -out:SetFont(ide.font.oNormal) -out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal) -out:SetBufferedDraw(not ide.config.hidpi and true or false) -out:StyleClearAll() - -out:SetTabWidth(ide.config.editor.tabwidth or 2) -out:SetIndent(ide.config.editor.tabwidth or 2) -out:SetUseTabs(ide.config.editor.usetabs and true or false) -out:SetViewWhiteSpace(ide.config.editor.whitespace and true or false) -out:SetIndentationGuides(true) - -out:SetWrapMode(wxstc.wxSTC_WRAP_WORD) -out:SetWrapStartIndent(0) -out:SetWrapVisualFlagsLocation(wxstc.wxSTC_WRAPVISUALFLAGLOC_END_BY_TEXT) -out:SetWrapVisualFlags(wxstc.wxSTC_WRAPVISUALFLAG_END) - -out:MarkerDefine(StylesGetMarker("prompt")) -out:MarkerDefine(StylesGetMarker("error")) -out:MarkerDefine(StylesGetMarker("output")) -out:MarkerDefine(StylesGetMarker("message")) -out:SetReadOnly(false) - -SetupKeywords(out,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic) - -local function getPromptLine() - local totalLines = out:GetLineCount() - return out:MarkerPrevious(totalLines+1, PROMPT_MARKER_VALUE) -end - -local function getPromptText() - local prompt = getPromptLine() - return out:GetTextRangeDyn(out:PositionFromLine(prompt), out:GetLength()) -end - -local function setPromptText(text) - local length = out:GetLength() - out:SetSelectionStart(length - string.len(getPromptText())) - out:SetSelectionEnd(length) - out:ClearAny() - out:AddTextDyn(text) - -- refresh the output window to force recalculation of wrapped lines; - -- otherwise a wrapped part of the last line may not be visible. - out:Update(); out:Refresh() - out:GotoPos(out:GetLength()) -end - -local function positionInLine(line) - return out:GetCurrentPos() - out:PositionFromLine(line) -end - -local function caretOnPromptLine(disallowLeftmost, line) - local promptLine = getPromptLine() - local currentLine = line or out:GetCurrentLine() - local boundary = disallowLeftmost and 0 or -1 - return (currentLine > promptLine - or currentLine == promptLine and positionInLine(promptLine) > boundary) -end - -local function chomp(line) return (line:gsub("%s+$", "")) end - -local function getInput(line) - local nextMarker = line - local count = out:GetLineCount() - - repeat -- check until we find at least some marker - nextMarker = nextMarker+1 - until out:MarkerGet(nextMarker) > 0 or nextMarker > count-1 - return chomp(out:GetTextRangeDyn( - out:PositionFromLine(line), out:PositionFromLine(nextMarker))) -end - -function ConsoleSelectCommand(point) - local cpos = out:ScreenToClient(point or wx.wxGetMousePosition()) - local position = out:PositionFromPoint(cpos) - if position == wxstc.wxSTC_INVALID_POSITION then return end - - local promptline = out:MarkerPrevious(out:LineFromPosition(position), PROMPT_MARKER_VALUE) - if promptline == wxstc.wxSTC_INVALID_POSITION then return end - local nextline = out:MarkerNext(promptline+1, ANY_MARKER_VALUE) - local epos = nextline ~= wxstc.wxSTC_INVALID_POSITION and out:PositionFromLine(nextline) or out:GetLength() - out:SetSelection(out:PositionFromLine(promptline), epos) - return true -end - -local currentHistory -local function getNextHistoryLine(forward, promptText) - local count = out:GetLineCount() - if currentHistory == nil then currentHistory = count end - - if forward then - currentHistory = out:MarkerNext(currentHistory+1, PROMPT_MARKER_VALUE) - if currentHistory == -1 then - currentHistory = count - return "" - end - else - currentHistory = out:MarkerPrevious(currentHistory-1, PROMPT_MARKER_VALUE) - if currentHistory == -1 then - return "" - end - end - -- need to skip the current prompt line - -- or skip repeated commands - if currentHistory == getPromptLine() - or getInput(currentHistory) == promptText then - return getNextHistoryLine(forward, promptText) - end - return getInput(currentHistory) -end - -local function getNextHistoryMatch(promptText) - local count = out:GetLineCount() - if currentHistory == nil then currentHistory = count end - - local current = currentHistory - while true do - currentHistory = out:MarkerPrevious(currentHistory-1, PROMPT_MARKER_VALUE) - if currentHistory == -1 then -- restart search from the last item - currentHistory = count - elseif currentHistory ~= getPromptLine() then -- skip current prompt - local input = getInput(currentHistory) - if input:find(promptText, 1, true) == 1 then return input end - end - -- couldn't find anything and made a loop; get out - if currentHistory == current then return end - end - - assert(false, "getNextHistoryMatch coudn't find a proper match") -end - -local function shellPrint(marker, ...) - local cnt = select('#',...) - if cnt == 0 then return end -- return if nothing to print - - local isPrompt = marker and (getPromptLine() > -1) - - local text = '' - for i=1,cnt do - local x = select(i,...) - text = text .. tostring(x)..(i < cnt and "\t" or "") - end - - -- split the text into smaller chunks as one large line - -- is difficult to handle for the editor - local prev, maxlength = 0, ide.config.debugger.maxdatalength - if #text > maxlength and not text:find("\n.") then - text = text:gsub("()(%s+)", function(p, s) - if p-prev >= maxlength then - prev = p - return "\n" - else - return s - end - end) - end - - -- add "\n" if it is missing - text = text:gsub("\n+$", "") .. "\n" - - local lines = out:GetLineCount() - local promptLine = isPrompt and getPromptLine() or nil - local insertLineAt = isPrompt and getPromptLine() or out:GetLineCount()-1 - local insertAt = isPrompt and out:PositionFromLine(getPromptLine()) or out:GetLength() - out:InsertTextDyn(insertAt, out.useraw and text or FixUTF8(text, function (s) return '\\'..string.byte(s) end)) - local linesAdded = out:GetLineCount() - lines - - if marker then - if promptLine then out:MarkerDelete(promptLine, PROMPT_MARKER) end - for line = insertLineAt, insertLineAt + linesAdded - 1 do - out:MarkerAdd(line, marker) - end - if promptLine then out:MarkerAdd(promptLine+linesAdded, PROMPT_MARKER) end - end - - out:EmptyUndoBuffer() -- don't allow the user to undo shell text - out:GotoPos(out:GetLength()) - out:EnsureVisibleEnforcePolicy(out:GetLineCount()-1) -end - -DisplayShell = function (...) - shellPrint(OUTPUT_MARKER, ...) -end -DisplayShellErr = function (...) - shellPrint(ERROR_MARKER, ...) -end -DisplayShellMsg = function (...) - shellPrint(MESSAGE_MARKER, ...) -end -DisplayShellDirect = function (...) - shellPrint(nil, ...) -end -DisplayShellPrompt = function (...) - -- don't print anything; just mark the line with a prompt mark - out:MarkerAdd(out:GetLineCount()-1, PROMPT_MARKER) -end - -local function filterTraceError(err, addedret) - local err = err:match("(.-:%d+:.-)\n[^\n]*\n[^\n]*\n[^\n]*src/editor/shellbox.lua:.*in function 'executeShellCode'") - or err - err = err:gsub("stack traceback:.-\n[^\n]+\n?","") - if addedret then err = err:gsub('^%[string "return ', '[string "') end - err = err:match("(.*)\n[^\n]*%(tail call%): %?$") or err - return err -end - -local function createenv () - local env = {} - setmetatable(env,{__index = _G}) - - local function luafilename(level) - level = level and level + 1 or 2 - local src - while (true) do - src = debug.getinfo(level) - if (src == nil) then return nil,level end - if (string.byte(src.source) == string.byte("@")) then - return string.sub(src.source,2),level - end - level = level + 1 - end - end - - local function luafilepath(level) - local src,level = luafilename(level) - if (src == nil) then return src,level end - src = string.gsub(src,"[\\/][^\\//]*$","") - return src,level - end - - local function relativeFilename(file) - assert(type(file)=='string',"String as filename expected") - local name = file - local level = 3 - while (name) do - if (wx.wxFileName(name):FileExists()) then return name end - name,level = luafilepath(level) - if (name == nil) then break end - name = name .. "/" .. file - end - - return file - end - - local function relativeFilepath(file) - local name = luafilepath(3) - return (file and name) and name.."/"..file or file or name - end - - local _loadfile = loadfile - local function loadfile(file) - assert(type(file)=='string',"String as filename expected") - local name = relativeFilename(file) - - return _loadfile(name) - end - - local function dofile(file, ...) - assert(type(file) == 'string',"String as filename expected") - local fn,err = loadfile(file) - local args = {...} - if not fn then - DisplayShellErr(err) - else - setfenv(fn,env) - return fn(unpack(args)) - end - end - - local os = { exit = function() - ide.frame:AddPendingEvent(wx.wxCommandEvent( - wx.wxEVT_COMMAND_MENU_SELECTED, ID_EXIT)) - end } - env.os = setmetatable(os, {__index = _G.os}) - env.print = DisplayShell - env.dofile = dofile - env.loadfile = loadfile - env.RELFILE = relativeFilename - env.RELPATH = relativeFilepath - - return env -end - -local env = createenv() - -function ShellSetAlias(alias, table) - local value = env[alias] - env[alias] = table - return value -end - -local function packResults(status, ...) return status, {...} end - -local function executeShellCode(tx) - if tx == nil or tx == '' then return end - - local forcelocalprefix = '^!' - local forcelocal = tx:find(forcelocalprefix) - tx = tx:gsub(forcelocalprefix, '') - - DisplayShellPrompt('') - - -- try to compile as statement - local _, err = loadstring(tx) - local isstatement = not err - - if remotesend and not forcelocal then remotesend(tx, isstatement); return end - - local addedret, forceexpression = true, tx:match("^%s*=%s*") - tx = tx:gsub("^%s*=%s*","") - local fn - fn, err = loadstring("return "..tx) - if not forceexpression and err then - fn, err = loadstring(tx) - addedret = false - end - - if fn == nil and err then - DisplayShellErr(filterTraceError(err, addedret)) - elseif fn then - setfenv(fn,env) - - -- set the project dir as the current dir to allow "require" calls - -- to work from shell - local projectDir, cwd = FileTreeGetDir(), nil - if projectDir and #projectDir > 0 then - cwd = wx.wxFileName.GetCwd() - wx.wxFileName.SetCwd(projectDir) - end - - local ok, res = packResults(xpcall(fn, - function(err) - DisplayShellErr(filterTraceError(debug.traceback(err), addedret)) - end)) - - -- restore the current dir - if cwd then wx.wxFileName.SetCwd(cwd) end - - if ok and (addedret or #res > 0) then - if addedret then - local mobdebug = require "mobdebug" - for i,v in pairs(res) do -- stringify each of the returned values - res[i] = (forceexpression and i > 1 and '\n' or '') .. - mobdebug.line(v, {nocode = true, comment = 1, - -- if '=' is used, then use multi-line serialized output - indent = forceexpression and ' ' or nil}) - end - -- add nil only if we are forced (using =) or if this is not a statement - -- this is needed to print 'nil' when asked for 'foo', - -- and don't print it when asked for 'print(1)' - if #res == 0 and (forceexpression or not isstatement) then - res = {'nil'} - end - end - DisplayShell(unpack(res)) - end - end -end - -function ShellSupportRemote(client) - remotesend = client - - local index = bottomnotebook:GetPageIndex(out) - if index then - bottomnotebook:SetPageText(index, - client and TR("Remote console") or TR("Local console")) - end -end - -function ShellExecuteFile(wfilename) - if (not wfilename) then return end - local cmd = 'dofile([['..wfilename:GetFullPath()..']])' - ShellExecuteCode(cmd) -end - -ShellExecuteInline = executeShellCode -function ShellExecuteCode(code) - local index = bottomnotebook:GetPageIndex(bottomnotebook.shellbox) - if ide.config.activateoutput and bottomnotebook:GetSelection() ~= index then - bottomnotebook:SetSelection(index) - end - - DisplayShellDirect(code) - executeShellCode(code) -end - -local function displayShellIntro() - DisplayShellMsg(TR("Welcome to the interactive Lua interpreter.").." " - ..TR("Enter Lua code and press Enter to run it.").."\n" - ..TR("Use Shift-Enter for multiline code.").." " - ..TR("Use 'clear' to clear the shell output and the history.").."\n" - ..TR("Prepend '=' to show complex values on multiple lines.").." " - ..TR("Prepend '!' to force local execution.")) - DisplayShellPrompt('') -end - -out:Connect(wx.wxEVT_KEY_DOWN, - function (event) - -- this loop is only needed to allow to get to the end of function easily - -- "return" aborts the processing and ignores the key - -- "break" aborts the processing and processes the key normally - while true do - local key = event:GetKeyCode() - if key == wx.WXK_UP or key == wx.WXK_NUMPAD_UP then - -- if we are below the prompt line, then allow to go up - -- through multiline entry - if out:GetCurrentLine() > getPromptLine() then break end - - -- if we are not on the caret line, move normally - if not caretOnPromptLine() then break end - - local promptText = getPromptText() - setPromptText(getNextHistoryLine(false, promptText)) - return - elseif key == wx.WXK_DOWN or key == wx.WXK_NUMPAD_DOWN then - -- if we are above the last line, then allow to go down - -- through multiline entry - local totalLines = out:GetLineCount()-1 - if out:GetCurrentLine() < totalLines then break end - - -- if we are not on the caret line, move normally - if not caretOnPromptLine() then break end - - local promptText = getPromptText() - setPromptText(getNextHistoryLine(true, promptText)) - return - elseif key == wx.WXK_TAB then - -- if we are above the prompt line, then don't move - local promptline = getPromptLine() - if out:GetCurrentLine() < promptline then return end - - local promptText = getPromptText() - -- save the position in the prompt text to restore - local pos = out:GetCurrentPos() - local text = promptText:sub(1, positionInLine(promptline)) - if #text == 0 then return end - - -- find the next match and set the prompt text - local match = getNextHistoryMatch(text) - if match then - setPromptText(match) - -- restore the position to make it easier to find the next match - out:GotoPos(pos) - end - return - elseif key == wx.WXK_ESCAPE then - setPromptText("") - return - elseif key == wx.WXK_BACK then - if not caretOnPromptLine(true) then return end - elseif key == wx.WXK_DELETE or key == wx.WXK_NUMPAD_DELETE then - if not caretOnPromptLine() - or out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then - return - end - elseif key == wx.WXK_PAGEUP or key == wx.WXK_NUMPAD_PAGEUP - or key == wx.WXK_PAGEDOWN or key == wx.WXK_NUMPAD_PAGEDOWN - or key == wx.WXK_END or key == wx.WXK_NUMPAD_END - or key == wx.WXK_HOME or key == wx.WXK_NUMPAD_HOME - or key == wx.WXK_LEFT or key == wx.WXK_NUMPAD_LEFT - or key == wx.WXK_RIGHT or key == wx.WXK_NUMPAD_RIGHT - or key == wx.WXK_SHIFT or key == wx.WXK_CONTROL - or key == wx.WXK_ALT then - break - elseif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER then - if not caretOnPromptLine() - or out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then - return - end - - -- allow multiline entry for shift+enter - if caretOnPromptLine(true) and event:ShiftDown() then break end - - local promptText = getPromptText() - if #promptText == 0 then return end -- nothing to execute, exit - if promptText == 'clear' then - out:Erase() - else - DisplayShellDirect('\n') - executeShellCode(promptText) - end - currentHistory = getPromptLine() -- reset history - return -- don't need to do anything else with return - else - -- move cursor to end if not already there - if not caretOnPromptLine() then - out:GotoPos(out:GetLength()) - -- check if the selection starts before the prompt line and reset it - elseif out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then - out:GotoPos(out:GetLength()) - out:SetSelection(out:GetSelectionEnd()+1,out:GetSelectionEnd()) - end - end - break - end - event:Skip() - end) - -local function inputEditable(line) - return caretOnPromptLine(false, line) and - not (out:LineFromPosition(out:GetSelectionStart()) < getPromptLine()) -end - --- new Scintilla (3.2.1) changed the way markers move when the text is updated --- ticket: http://sourceforge.net/p/scintilla/bugs/939/ --- discussion: https://groups.google.com/forum/?hl=en&fromgroups#!topic/scintilla-interest/4giFiKG4VXo -if ide.wxver >= "2.9.5" then - -- this is a workaround that stores a position of the last prompt marker - -- before insert and restores the same position after (as the marker) - -- could have moved if the text is added at the beginning of the line. - local promptAt - out:Connect(wxstc.wxEVT_STC_MODIFIED, - function (event) - local evtype = event:GetModificationType() - if bit.band(evtype, wxstc.wxSTC_MOD_BEFOREINSERT) ~= 0 then - local promptLine = getPromptLine() - if promptLine and event:GetPosition() == out:PositionFromLine(promptLine) - then promptAt = promptLine end - end - if bit.band(evtype, wxstc.wxSTC_MOD_INSERTTEXT) ~= 0 then - local promptLine = getPromptLine() - if promptLine and promptAt then - out:MarkerDelete(promptLine, PROMPT_MARKER) - out:MarkerAdd(promptAt, PROMPT_MARKER) - promptAt = nil - end - end - end) -end - -out:Connect(wxstc.wxEVT_STC_UPDATEUI, - function (event) out:SetReadOnly(not inputEditable()) end) - --- only allow copy/move text by dropping to the input line -out:Connect(wxstc.wxEVT_STC_DO_DROP, - function (event) - if not inputEditable(out:LineFromPosition(event:GetPosition())) then - event:SetDragResult(wx.wxDragNone) - end - end) - -if ide.config.outputshell.nomousezoom then - -- disable zoom using mouse wheel as it triggers zooming when scrolling - -- on OSX with kinetic scroll and then pressing CMD. - out:Connect(wx.wxEVT_MOUSEWHEEL, - function (event) - if wx.wxGetKeyState(wx.WXK_CONTROL) then return end - event:Skip() - end) -end - -displayShellIntro() - -function out:Erase() - self:ClearAll() - displayShellIntro() -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/singleinstance.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/singleinstance.lua deleted file mode 100644 index 450cb6f..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/singleinstance.lua +++ /dev/null @@ -1,98 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local ide = ide ---[[ single instance -open an UDP port - if it fails it is either because -- IDE is running already -- an application is already blocking that port -if it fails it tries to contact the running application -- if it confirms being the IDE we let that instance open it, finish our application -- otherwise we throw an error message on the user and start like normal - -probably a pitfal: an instance is running but is not visible - (because it was finished though the UDP thing still runs) -]] - -if not ide.config.singleinstance then return end - -local socket = require "socket" -local port = ide.config.singleinstanceport -local delay = tonumber(ide.config.singleinstance) or 1000 -- in ms -local svr = socket.udp() -local success = svr:setsockname("127.0.0.1",port) -- bind on local host -local protocol = {client = {}, server = {}} - -protocol.client.greeting = "Is this you, my IDE? It's me, a new instance." -protocol.server.greeting = "Yes it is me, running as: %s" -protocol.client.requestloading = "Could you please load this file for me: %s" -protocol.server.answerok = "Sure. You may now leave." - -if success then -- ok, server was started, we are solo - --TODO: if multiple files are to be opened, each file is handled one by one - we could create a single string instead... - ide.idletimer = wx.wxTimer(wx.wxGetApp()) - ide.idletimer:Start(delay,false) - svr:settimeout(0) -- don't block - wx.wxGetApp():Connect(wx.wxEVT_TIMER, function() - if ide.exitingProgram then -- if exiting, terminate the timer loop - wx.wxGetApp():Disconnect(wx.wxEVT_TIMER) - return - end - - local msg, ip, port = svr:receivefrom() - if msg then - if msg == protocol.client.greeting then - svr:sendto(protocol.server.greeting:format(wx.wxGetUserName()),ip,port) - elseif msg:match(protocol.client.requestloading:gsub("%%s",".+$")) then -- ok we need to open something - svr:sendto(protocol.server.answerok,ip,port) - local filename = msg:match(protocol.client.requestloading:gsub("%%s","(.+)$")) - if filename then - RequestAttention() - if wx.wxDirExists(filename) then - ProjectUpdateProjectDir(filename) - elseif not ActivateFile(filename) then - DisplayOutputLn(TR("Can't open file '%s': %s"):format(filename, wx.wxSysErrorMsg())) - end - end - end - end - end) -else -- something different is running on our port - local cln = socket.udp() - cln:setpeername("127.0.0.1",port) - cln:settimeout(2) - cln:send(protocol.client.greeting) - - local msg = cln:receive() - local arg = ide.arg - if msg and msg:match(protocol.server.greeting:gsub("%%s",".+$")) then - local username = msg:match(protocol.server.greeting:gsub("%%s","(.+)$")) - if username ~= wx.wxGetUserName() then - print(("Another instance is running under user '%s' and can't be activated. This instance will continue running, which may cause interference with the debugger."):format(username)) - else - local failed = false - for index = 2, #arg do - local fileName = arg[index] - if fileName ~= "--" - -- on OSX, the command line includes -psn parameter, so ignore it - and (ide.osname ~= 'Macintosh' or not fileName:find("^-psn")) then - cln:send(protocol.client.requestloading:format(fileName)) - - local msg, err = cln:receive() - if msg ~= protocol.server.answerok then - failed = true - print(err,msg) - end - end - end - if failed then - print("The server instance failed to open the files, this instance will continue running.") - else -- done - os.exit(0) - end - end - else - print("The single instance communication has failed; there may be another instance running, which may cause interference with the debugger.") - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/style.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/style.lua deleted file mode 100644 index 077fa41..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/style.lua +++ /dev/null @@ -1,441 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- ----------- --- Style --- --- common style attributes --- --------------------------- --- fg foreground - {r,g,b} 0-255 --- bg background - {r,g,b} 0-255 --- alpha translucency - 0-255 (0 - transparent, 255 - opaque, 256 - opaque/faster) --- sel color of the selected block - {r,g,b} 0-255 (only applies to folds) --- u underline - boolean --- b bold - boolean --- i italic - boolean --- fill fill to end - boolean --- fn font Face Name - string ("Lucida Console") --- fs font size - number (11) --- hs turn hotspot on - true or {r,g,b} 0-255 --- v visibility for symbols of the current style - boolean - -local unpack = table.unpack or unpack - -function StylesGetDefault() - return { - -- lexer specific (inherit fg/bg from text) - lexerdef = {fg = {160, 160, 160}}, - comment = {fg = {128, 128, 128}}, - stringtxt = {fg = {128, 32, 16}}, - stringeol = {fg = {128, 32, 16}, bg = {224, 192, 224}, fill = true}, - preprocessor = {fg = {128, 128, 0}}, - operator = {fg = {64, 64, 64}}, - number = {fg = {80, 112, 255}}, - - keywords0 = {fg = {32, 32, 192}}, - keywords1 = {fg = {127, 32, 96}}, - keywords2 = {fg = {32, 127, 96}}, - keywords3 = {fg = {64, 32, 96}}, - keywords4 = {fg = {127, 0, 95}}, - keywords5 = {fg = {35, 95, 175}}, - keywords6 = {fg = {0, 127, 127}}, - keywords7 = {fg = {240, 255, 255}}, - - -- common (inherit fg/bg from text) - text = {fg = {64, 64, 64}, bg = {250, 250, 250}}, - linenumber = {fg = {128, 128, 128}, bg = {250, 250, 250}}, - bracematch = {fg = {32, 128, 255}, b = true}, - bracemiss = {fg = {255, 128, 32}, b = true}, - ctrlchar = nil, - indent = {fg = {192, 192, 230}, bg = {255, 255, 255}}, - calltip = nil, - - -- common special (need custom fg & bg) - sel = {bg = {208, 208, 208}}, - caret = {fg = {0, 0, 0}}, - caretlinebg = {bg = {240, 240, 230}}, - fold = {fg = {192, 192, 192}, bg = {250, 250, 250}, sel = {160, 128, 224}}, - whitespace = nil, - edge = {}, - - -- deprecated; allowed for backward compatibility in case someone does - -- fncall.fg = {...} - fncall = {}, - - -- markup - ['|'] = {fg = {127, 0, 127}}, - ['`'] = {fg = {64, 128, 64}}, - ['['] = {hs = {32, 32, 127}}, - - -- markers - marker = { - currentline = {}, - breakpoint = {}, - message = {}, - output = {}, - prompt = {}, - error = {}, - searchmatchfile = {}, - }, - - -- indicators - indicator = { - fncall = {}, - varlocal = {}, - varglobal = {}, - varmasking = {}, - varmasked = {}, - searchmatch = {}, - }, - } -end - -local markers = { - breakpoint = {0, wxstc.wxSTC_MARK_CIRCLE, wx.wxColour(196, 64, 64), wx.wxColour(220, 64, 64)}, - bookmark = {1, wxstc.wxSTC_MARK_SHORTARROW, wx.wxColour(16, 96, 128), wx.wxColour(96, 160, 220)}, - currentline = {2, wxstc.wxSTC_MARK_ARROW, wx.wxColour(16, 128, 16), wx.wxColour(64, 220, 64)}, - message = {3, wxstc.wxSTC_MARK_CHARACTER+(' '):byte(), wx.wxBLACK, wx.wxColour(220, 220, 220)}, - output = {4, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(240, 240, 240)}, - prompt = {5, wxstc.wxSTC_MARK_ARROWS, wx.wxBLACK, wx.wxColour(220, 220, 220)}, - error = {6, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(255, 220, 220)}, - searchmatchfile = {7, wxstc.wxSTC_MARK_EMPTY, wx.wxBLACK, wx.wxColour(196, 0, 0)}, -} -function StylesGetMarker(marker) return unpack(markers[marker] or {}) end -function StylesRemoveMarker(marker) markers[marker] = nil end -function StylesAddMarker(marker, ch, fg, bg) - local num = (markers[marker] or {})[1] - if not num then -- new marker; find the smallest available marker number - local nums = {} - for _, mark in pairs(markers) do nums[mark[1]] = true end - num = #nums + 1 - if num > 24 then return end -- 24 markers with no pre-defined functions - end - markers[marker] = {num, ch, wx.wxColour(unpack(fg)), wx.wxColour(unpack(bg))} - return num -end - -local function applymarker(editor,marker,clrfg,clrbg,clrsel) - if (clrfg) then editor:MarkerSetForeground(marker,clrfg) end - if (clrbg) then editor:MarkerSetBackground(marker,clrbg) end - if (ide.wxver >= "2.9.5" and clrsel) then editor:MarkerSetBackgroundSelected(marker,clrsel) end -end -local specialmapping = { - sel = function(editor,style) - if (style.fg) then - editor:SetSelForeground(1,wx.wxColour(unpack(style.fg))) - else - editor:SetSelForeground(0,wx.wxWHITE) - end - if (style.bg) then - editor:SetSelBackground(1,wx.wxColour(unpack(style.bg))) - else - editor:SetSelBackground(0,wx.wxWHITE) - end - if (style.alpha and ide.wxver >= "2.9.5") then - editor:SetSelAlpha(style.alpha) - end - - -- set alpha for additional selecton: 0 - transparent, 255 - opaque - if ide.wxver >= "2.9.5" then editor:SetAdditionalSelAlpha(127) end - end, - - seladd = function(editor,style) - if ide.wxver >= "2.9.5" then - if (style.fg) then - editor:SetAdditionalSelForeground(wx.wxColour(unpack(style.fg))) - end - if (style.bg) then - editor:SetAdditionalSelBackground(wx.wxColour(unpack(style.bg))) - end - if (style.alpha) then - editor:SetAdditionalSelAlpha(style.alpha) - end - end - end, - - caret = function(editor,style) - if (style.fg) then - editor:SetCaretForeground(wx.wxColour(unpack(style.fg))) - end - end, - - caretlinebg = function(editor,style) - if (style.bg) then - editor:SetCaretLineBackground(wx.wxColour(unpack(style.bg))) - end - if (style.alpha and ide.wxver >= "2.9.5") then - editor:SetCaretLineBackAlpha(style.alpha) - end - end, - - whitespace = function(editor,style) - if (style.fg) then - editor:SetWhitespaceForeground(1,wx.wxColour(unpack(style.fg))) - else - --editor:SetWhitespaceForeground(0) - end - if (style.bg) then - editor:SetWhitespaceBackground(1,wx.wxColour(unpack(style.bg))) - else - --editor:SetWhitespaceBackground(0) - end - end, - - fold = function(editor,style) - local clrfg = style.fg and wx.wxColour(unpack(style.fg)) - local clrbg = style.bg and wx.wxColour(unpack(style.bg)) - local clrhi = style.hi and wx.wxColour(unpack(style.hi)) - local clrsel = style.sel and wx.wxColour(unpack(style.sel)) - - -- if selected background is set then enable support for it - if ide.wxver >= "2.9.5" and clrsel then editor:MarkerEnableHighlight(true) end - - if (clrfg or clrbg or clrsel) then - -- foreground and background are defined as opposite to what I'd expect - -- for fold markers in Scintilla's terminilogy: - -- background is the color of fold lines/boxes and foreground is the color - -- of everything around fold lines or inside fold boxes. - -- in the following code fg and bg are simply reversed - local clrfg, clrbg = clrbg, clrfg - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPEN, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDER, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERSUB, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERTAIL, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEREND, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPENMID, clrfg, clrbg, clrsel) - applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, clrfg, clrbg, clrsel) - end - if clrbg then - -- the earlier calls only color the actual markers, but not the - -- overall fold background; SetFoldMargin calls below do this. - -- http://community.activestate.com/forum-topic/fold-margin-colors - -- http://www.scintilla.org/ScintillaDoc.html#SCI_SETFOLDMARGINCOLOUR - editor:SetFoldMarginColour(true, clrbg) - editor:SetFoldMarginHiColour(true, clrbg) - end - if clrhi then - editor:SetFoldMarginHiColour(true, clrhi) - end - end, - - edge = function(editor,style) - if style.fg or style.col or style.mode then - editor:SetEdgeColour(wx.wxColour(unpack(style.fg or {220, 220, 220}))) - editor:SetEdgeMode(style.mode or wxstc.wxSTC_EDGE_LINE) - editor:SetEdgeColumn(style.col or 80) - end - end, - - marker = function(editor,markers) - for m, style in pairs(markers) do - local id, ch, fg, bg = StylesGetMarker(m) - if style.ch then ch = style.ch end - if style.fg then fg = wx.wxColour(unpack(style.fg)) end - if style.bg then bg = wx.wxColour(unpack(style.bg)) end - editor:MarkerDefine(id, ch, fg, bg) - end - end, - - auxwindow = function(editor,style) - if not style then return end - - -- don't color toolbars as they have their own color/style - local skipcolor = {wxAuiToolBar = true, wxToolBar = true} - local default = wxstc.wxSTC_STYLE_DEFAULT - local bg = style.bg and wx.wxColour(unpack(style.bg)) or editor:StyleGetBackground(default) - local fg = style.fg and wx.wxColour(unpack(style.fg)) or editor:StyleGetForeground(default) - - local uimgr = ide.frame.uimgr - local panes = uimgr:GetAllPanes() - for index = 0, panes:GetCount()-1 do - local wind = uimgr:GetPane(panes:Item(index).name).window - - -- wxlua compiled with STL doesn't provide GetChildren() method - -- as per http://sourceforge.net/p/wxlua/mailman/message/32500995/ - local ok, children = pcall(function() return wind:GetChildren() end) - if not ok then break end - - for child = 0, children:GetCount()-1 do - local data = children:Item(child):GetData() - local _, window = pcall(function() return data:DynamicCast("wxWindow") end) - if window and not skipcolor[window:GetClassInfo():GetClassName()] then - window:SetBackgroundColour(bg) - window:SetForegroundColour(fg) - window:Refresh() - end - end - end - end, -} - -local defaultmapping = { - text = wxstc.wxSTC_STYLE_DEFAULT, - linenumber = wxstc.wxSTC_STYLE_LINENUMBER, - bracematch = wxstc.wxSTC_STYLE_BRACELIGHT, - bracemiss = wxstc.wxSTC_STYLE_BRACEBAD, - ctrlchar = wxstc.wxSTC_STYLE_CONTROLCHAR, - indent = wxstc.wxSTC_STYLE_INDENTGUIDE, - calltip = wxstc.wxSTC_STYLE_CALLTIP, -} - -function StylesApplyToEditor(styles,editor,font,fontitalic,lexerconvert) - local defaultfg = styles.text and styles.text.fg and wx.wxColour(unpack(styles.text.fg)) or nil - local defaultbg = styles.text and styles.text.bg and wx.wxColour(unpack(styles.text.bg)) or nil - - local function applystyle(style,id) - editor:StyleSetFont(id, style.i and fontitalic or font) - editor:StyleSetBold(id, style.b or false) - editor:StyleSetUnderline(id, style.u or false) - editor:StyleSetEOLFilled(id, style.fill or false) - - if style.fn then editor:StyleSetFaceName(id, style.fn) end - if style.fs then editor:StyleSetSize(id, style.fs) end - if style.v ~= nil then editor:StyleSetVisible(id, style.v) end - - if style.hs then - editor:StyleSetHotSpot(id, 1) - -- if passed a color (table) as value, set it as foreground - if type(style.hs) == 'table' then - local color = wx.wxColour(unpack(style.hs)) - editor:SetHotspotActiveForeground(1, color) - end - editor:SetHotspotActiveUnderline(1) - editor:SetHotspotSingleLine(1) - end - - if (style.fg or defaultfg) then - editor:StyleSetForeground(id, style.fg and wx.wxColour(unpack(style.fg)) or defaultfg) - end - if (style.bg or defaultbg) then - editor:StyleSetBackground(id, style.bg and wx.wxColour(unpack(style.bg)) or defaultbg) - end - end - - editor:StyleResetDefault() - editor:SetFont(font) - if (styles.text) then - applystyle(styles.text,defaultmapping["text"]) - else - applystyle({},defaultmapping["text"]) - end - editor:StyleClearAll() - - -- set the default linenumber font size based on the editor font size - if styles.linenumber and not styles.linenumber.fs then - styles.linenumber.fs = ide.config.editor.fontsize and (ide.config.editor.fontsize - 1) or nil - end - - for name,style in pairs(styles) do - if (specialmapping[name]) then - specialmapping[name](editor,style) - elseif (defaultmapping[name]) then - applystyle(style,defaultmapping[name]) - end - - if (lexerconvert and lexerconvert[name]) then - local targets = lexerconvert[name] - for _, outid in pairs(targets) do - applystyle(style,outid) - end - -- allow to specify style numbers, but exclude those styles - -- that may conflict with indicator numbers - elseif (style.st and style.st > 8 and style.st < wxstc.wxSTC_STYLE_DEFAULT) then - applystyle(style,style.st) - end - end - - -- additional selection (seladd) attributes can only be set after - -- normal selection (sel) attributes are set, so handle them again - if styles.seladd then specialmapping.seladd(editor, styles.seladd) end - - -- calltip has a special style that needs to be enabled - if styles.calltip then editor:CallTipUseStyle(2) end - - do - local defaultfg = {127,127,127} - local indic = styles.indicator or {} - - -- use styles.fncall if not empty and if indic.fncall is empty - -- for backward compatibility - if type(styles.fncall) == 'table' and next(styles.fncall) - and not (type(indic.fncall) == 'table' and next(indic.fncall)) then indic.fncall = styles.fncall end - - local fncall = ide:AddIndicator("core.fncall") - local varlocal = ide:AddIndicator("core.varlocal") - local varglobal = ide:AddIndicator("core.varglobal") - local varmasking = ide:AddIndicator("core.varmasking") - local varmasked = ide:AddIndicator("core.varmasked") - local searchmatch = ide:AddIndicator("core.searchmatch") - - editor:IndicatorSetStyle(fncall, indic.fncall and indic.fncall.st or ide.wxver >= "2.9.5" and wxstc.wxSTC_INDIC_ROUNDBOX or wxstc.wxSTC_INDIC_TT) - editor:IndicatorSetForeground(fncall, wx.wxColour(unpack(indic.fncall and indic.fncall.fg or {128, 128, 255}))) - editor:IndicatorSetStyle(varlocal, indic.varlocal and indic.varlocal.st or wxstc.wxSTC_INDIC_DOTS or wxstc.wxSTC_INDIC_TT) - editor:IndicatorSetForeground(varlocal, wx.wxColour(unpack(indic.varlocal and indic.varlocal.fg or defaultfg))) - editor:IndicatorSetStyle(varglobal, indic.varglobal and indic.varglobal.st or wxstc.wxSTC_INDIC_PLAIN) - editor:IndicatorSetForeground(varglobal, wx.wxColour(unpack(indic.varglobal and indic.varglobal.fg or defaultfg))) - editor:IndicatorSetStyle(varmasking, indic.varmasking and indic.varmasking.st or wxstc.wxSTC_INDIC_DASH or wxstc.wxSTC_INDIC_DIAGONAL) - editor:IndicatorSetForeground(varmasking, wx.wxColour(unpack(indic.varmasking and indic.varmasking.fg or defaultfg))) - editor:IndicatorSetStyle(varmasked, indic.varmasked and indic.varmasked.st or wxstc.wxSTC_INDIC_STRIKE) - editor:IndicatorSetForeground(varmasked, wx.wxColour(unpack(indic.varmasked and indic.varmasked.fg or defaultfg))) - editor:IndicatorSetStyle(searchmatch, indic.searchmatch and indic.searchmatch.st or wxstc.wxSTC_INDIC_BOX) - editor:IndicatorSetForeground(searchmatch, wx.wxColour(unpack(indic.searchmatch and indic.searchmatch.fg or {196, 0, 0}))) - end -end - -function ReApplySpecAndStyles() - -- re-register markup styles as they are special: - -- these styles need to be updated as they are based on comment styles - if MarkupAddStyles then MarkupAddStyles(ide.config.styles) end - - local errorlog = ide.frame.bottomnotebook.errorlog - local shellbox = ide.frame.bottomnotebook.shellbox - SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic) - StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic) - - for _, doc in pairs(ide:GetDocuments()) do - if doc.editor.spec then doc.editor:SetupKeywords(nil, doc.editor.spec) end - end -end - -function ApplyStyleConfig(config, style) - if not wx.wxIsAbsolutePath(config) - then config = MergeFullPath(GetPathWithSep(ide.editorFilename), config) end - - local cfg = {wxstc = wxstc, math = math, print = DisplayOutputLn, - path = {}, editor = {}, view ={}, acandtip = {}, outputshell = {}, debugger={}} - local cfgfn, err = loadfile(config) - if not cfgfn then - DisplayOutputLn(TR("Error while loading configuration file: %s"):format(err)) - return - end - - setfenv(cfgfn,cfg) - cfgfn, err = pcall(cfgfn,style) - if not cfgfn then - DisplayOutputLn(TR("Error while processing configuration file: %s"):format(err)) - return - end - - -- if no style assigned explicitly, but a table is returned, use it - if not (cfg.styles or cfg.stylesoutshell) and type(err) == 'table' then - cfg.styles = err - end - - if cfg.styles or cfg.stylesoutshell then - if (cfg.styles) then - ide.config.styles = StylesGetDefault() - -- copy - for i,s in pairs(cfg.styles) do - ide.config.styles[i] = s - end - end - if (cfg.stylesoutshell) then - ide.config.stylesoutshell = StylesGetDefault() - -- copy - for i,s in pairs(cfg.stylesoutshell) do - ide.config.stylesoutshell[i] = s - end - end - ReApplySpecAndStyles() - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/toolbar.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/toolbar.lua deleted file mode 100644 index e7dd878..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/editor/toolbar.lua +++ /dev/null @@ -1,55 +0,0 @@ --- Copyright 2014-15 Paul Kulchenko, ZeroBrane LLC - -local TR = function(...) return ... end - -ide.config.toolbar.icons = { - ID.NEW, ID.OPEN, ID.SAVE, ID.SAVEALL, ID.PROJECTDIRFROMFILE, ID.PROJECTDIRCHOOSE, - ID.SEPARATOR, - ID.FIND, ID.REPLACE, ID.FINDINFILES, - ID.SEPARATOR, - ID.RUN, ID.STARTDEBUG, ID.RUNNOW, ID.STOPDEBUG, ID.DETACHDEBUG, ID.BREAK, - ID.STEP, ID.STEPOVER, ID.STEPOUT, ID.RUNTO, - ID.SEPARATOR, - ID.BREAKPOINTTOGGLE, ID.BOOKMARKTOGGLE, ID.VIEWCALLSTACK, ID.VIEWWATCHWINDOW, - [ID.FINDINFILES] = false, -} - -ide.config.toolbar.iconmap = { - [ID.NEW] = {"FILE-NEW", TR("Create an empty document")}, - [ID.OPEN] = {"FILE-OPEN", TR("Open an existing document")}, - [ID.SAVE] = {"FILE-SAVE", TR("Save the current document")}, - [ID.SAVEALL] = {"FILE-SAVE-ALL", TR("Save all open documents")}, - [ID.PROJECTDIRFROMFILE]= {"DIR-SETUP-FILE", TR("Set project directory from current file")}, - [ID.PROJECTDIRCHOOSE] = {"DIR-SETUP", TR("Choose a project directory")}, - [ID.FIND] = {"FIND", TR("Find text")}, - [ID.REPLACE] = {"FIND-AND-REPLACE", TR("Find and replace text")}, - [ID.FINDINFILES] = {"FIND-IN-FILES", TR("Find in files")}, - [ID.RUN] = {"RUN", TR("Execute the current project/file")}, - [ID.RUNNOW] = {"RUN-NOW", TR("Run as Scratchpad")}, - [ID.STARTDEBUG] = {"DEBUG-START", TR("Start or continue debugging")}, - [ID.STOPDEBUG] = {"DEBUG-STOP", TR("Stop the currently running process")}, - [ID.DETACHDEBUG]= {"DEBUG-DETACH", TR("Stop debugging and continue running the process")}, - [ID.BREAK] = {"DEBUG-BREAK", TR("Break execution at the next executed line of code")}, - [ID.RUNTO] = {"DEBUG-RUN-TO", TR("Run to cursor")}, - [ID.STEP] = {"DEBUG-STEP-INTO", TR("Step into")}, - [ID.STEPOVER] = {"DEBUG-STEP-OVER", TR("Step over")}, - [ID.STEPOUT] = {"DEBUG-STEP-OUT", TR("Step out of the current function")}, - [ID.BREAKPOINTTOGGLE] = {"DEBUG-BREAKPOINT-TOGGLE", TR("Toggle breakpoint")}, - [ID.BOOKMARKTOGGLE] = {"BOOKMARK-TOGGLE", TR("Toggle bookmark")}, - [ID.VIEWCALLSTACK] = {"DEBUG-CALLSTACK", TR("View the stack window")}, - [ID.VIEWWATCHWINDOW] = {"DEBUG-WATCH", TR("View the watch window")}, - -- search toolbar - [ID.FINDNEXT] = {"FIND", TR("Find")}, - [ID.FINDREPLACENEXT] = {"FIND-REPLACE-NEXT", TR("Replace next instance")}, - [ID.FINDREPLACEALL] = {"FIND-AND-REPLACE", TR("Replace all")}, - [ID.FINDSETDIR] = {"FIND-OPT-SETDIR", TR("Set search directory")}, - [ID.FINDOPTDIRECTION] = {"FIND-OPT-DOWN", TR("Search direction")}, - [ID.FINDOPTWRAPWROUND] = {"FIND-OPT-WRAP-AROUND", TR("Wrap around")}, - [ID.FINDOPTSELECTION] = {"FIND-OPT-SELECTION", TR("Search in selection")}, - [ID.FINDOPTWORD] = {"FIND-OPT-WORD", TR("Match whole word")}, - [ID.FINDOPTCASE] = {"FIND-OPT-CASE-SENSITIVE", TR("Match case")}, - [ID.FINDOPTREGEX] = {"FIND-OPT-REGEX", TR("Regular expression")}, - [ID.FINDOPTCONTEXT] = {"FIND-OPT-CONTEXT", TR("Show context")}, - [ID.FINDOPTSUBDIR] = {"FIND-OPT-SUBDIR", TR("Search in subdirectories")}, - [ID.FINDOPTMULTIRESULTS] = {"FIND-OPT-MULTI-RESULTS", TR("Show multiple result windows")}, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/main.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/main.lua deleted file mode 100644 index 4d6b68c..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/main.lua +++ /dev/null @@ -1,774 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - --- put bin/ and lualibs/ first to avoid conflicts with included modules --- that may have other versions present somewhere else in path/cpath. -local function isproc() - local file = io.open("/proc") - if file then file:close() end - return file ~= nil -end -local iswindows = os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows') -local islinux = not iswindows and isproc() -local arch = "x86" -- use 32bit by default -local unpack = table.unpack or unpack - -if islinux then - local file = io.popen("uname -m") - if file then - local machine=file:read("*l") - local archtype= { x86_64="x64", armv7l="armhf" } - arch = archtype[machine] or "x86" - file:close() - end -end - -package.cpath = ( - iswindows and 'bin/?.dll;bin/clibs/?.dll;' or - islinux and ('bin/linux/%s/lib?.so;bin/linux/%s/clibs/?.so;'):format(arch,arch) or - --[[isosx]] 'bin/lib?.dylib;bin/clibs/?.dylib;') - .. package.cpath -package.path = 'lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;lualibs/?/?/?.lua;lualibs/?/?/init.lua;' - .. package.path - -require("wx") -require("bit") -require("mobdebug") -if jit and jit.on then jit.on() end -- turn jit "on" as "mobdebug" may turn it off for LuaJIT - -dofile "src/util.lua" - ------------ --- IDE --- -local pendingOutput = {} -ide = { - MODPREF = "* ", - MAXMARGIN = 4, - config = { - path = { - projectdir = "", - app = nil, - }, - editor = { - autoactivate = false, - foldcompact = true, - checkeol = true, - saveallonrun = false, - caretline = true, - showfncall = false, - autotabs = false, - usetabs = false, - tabwidth = 2, - usewrap = true, - wrapmode = wxstc.wxSTC_WRAP_WORD, - calltipdelay = 500, - smartindent = true, - fold = true, - autoreload = true, - indentguide = true, - backspaceunindent = true, - }, - debugger = { - verbose = false, - hostname = nil, - port = nil, - runonstart = nil, - redirect = nil, - maxdatalength = 400, - maxdatanum = 400, - maxdatalevel = 3, - }, - default = { - name = 'untitled', - fullname = 'untitled.lua', - interpreter = 'luadeb', - }, - outputshell = { - usewrap = true, - }, - filetree = { - mousemove = true, - }, - outline = { - jumptocurrentfunction = true, - showanonymous = '~', - showcurrentfunction = true, - showcompact = false, - showflat = false, - showmethodindicator = false, - showonefile = false, - sort = false, - }, - commandbar = { - prefilter = 250, -- number of records after which to apply filtering - maxitems = 30, -- max number of items to show - width = 0.35, -- <1 -- size in proportion to the app frame width; >1 -- size in pixels - showallsymbols = true, - }, - staticanalyzer = { - infervalue = false, -- off by default as it's a slower mode - }, - search = { - autocomplete = true, - contextlinesbefore = 2, - contextlinesafter = 2, - showaseditor = false, - zoom = 0, - autohide = false, - }, - print = { - magnification = -3, - wrapmode = wxstc.wxSTC_WRAP_WORD, - colourmode = wxstc.wxSTC_PRINT_BLACKONWHITE, - header = "%S\t%D\t%p/%P", - footer = nil, - }, - toolbar = { - icons = {}, - iconmap = {}, - }, - - keymap = {}, - imagemap = { - ['VALUE-MCALL'] = 'VALUE-SCALL', - }, - messages = {}, - language = "en", - - styles = nil, - stylesoutshell = nil, - - autocomplete = true, - autoanalyzer = true, - acandtip = { - shorttip = true, - nodynwords = true, - ignorecase = false, - symbols = true, - droprest = true, - strategy = 2, - width = 60, - maxlength = 450, - warning = true, - }, - arg = {}, -- command line arguments - api = {}, -- additional APIs to load - - format = { -- various formatting strings - menurecentprojects = "%f | %i", - apptitle = "%T - %F", - }, - - activateoutput = true, -- activate output/console on Run/Debug/Compile - unhidewindow = false, -- to unhide a gui window - projectautoopen = true, - autorecoverinactivity = 10, -- seconds - outlineinactivity = 0.250, -- seconds - markersinactivity = 0.500, -- seconds - symbolindexinactivity = 2, -- seconds - filehistorylength = 20, - projecthistorylength = 20, - bordersize = 2, - savebak = false, - singleinstance = false, - singleinstanceport = 0xe493, - showmemoryusage = false, - showhiddenfiles = false, - hidpi = false, -- HiDPI/Retina display support - hotexit = false, - -- file exclusion lists - excludelist = {".svn/", ".git/", ".hg/", "CVS/", "*.pyc", "*.pyo", "*.exe", "*.dll", "*.obj","*.o", "*.a", "*.lib", "*.so", "*.dylib", "*.ncb", "*.sdf", "*.suo", "*.pdb", "*.idb", ".DS_Store", "*.class", "*.psd", "*.db"}, - binarylist = {"*.jpg", "*.jpeg", "*.png", "*.gif", "*.ttf", "*.tga", "*.dds", "*.ico", "*.eot", "*.pdf", "*.swf", "*.jar", "*.zip", ".gz", ".rar"}, - }, - specs = { - none = { - sep = "\1", - } - }, - tools = {}, - iofilters = {}, - interpreters = {}, - packages = {}, - apis = {}, - timers = {}, - onidle = {}, - - proto = {}, -- prototypes for various classes - - app = nil, -- application engine - interpreter = nil, -- current Lua interpreter - frame = nil, -- gui related - debugger = {}, -- debugger related info - filetree = nil, -- filetree - findReplace = nil, -- find & replace handling - settings = nil, -- user settings (window pos, last files..) - session = { - projects = {}, -- project configuration for the current session - lastupdated = nil, -- timestamp of the last modification in any of the editors - lastsaved = nil, -- timestamp of the last recovery information saved - }, - - -- misc - exitingProgram = false, -- are we currently exiting, ID_EXIT - infocus = nil, -- last component with a focus - editorApp = wx.wxGetApp(), - editorFilename = nil, - openDocuments = {},-- open notebook editor documents[winId] = { - -- editor = wxStyledTextCtrl, - -- index = wxNotebook page index, - -- filePath = full filepath, nil if not saved, - -- fileName = just the filename, - -- modTime = wxDateTime of disk file or nil, - -- isModified = bool is the document modified? } - ignoredFilesList = {}, - font = { - eNormal = nil, - eItalic = nil, - oNormal = nil, - oItalic = nil, - fNormal = nil, - }, - - osname = wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName(), - osarch = arch, - oshome = os.getenv("HOME") or (iswindows and os.getenv('HOMEDRIVE') and os.getenv('HOMEPATH') - and (os.getenv('HOMEDRIVE')..os.getenv('HOMEPATH'))), - wxver = string.match(wx.wxVERSION_STRING, "[%d%.]+"), - - test = {}, -- local functions used for testing - - Print = function(self, ...) - if DisplayOutputLn then - -- flush any pending output - while #pendingOutput > 0 do DisplayOutputLn(unpack(table.remove(pendingOutput, 1))) end - -- print without parameters can be used for flushing, so skip the printing - if select('#', ...) > 0 then DisplayOutputLn(...) end - return - end - pendingOutput[#pendingOutput + 1] = {...} - end, -} - --- add wx.wxMOD_RAW_CONTROL as it's missing in wxlua 2.8.12.3; --- provide default for wx.wxMOD_CONTROL as it's missing in wxlua 2.8 that --- is available through Linux package managers -if not wx.wxMOD_CONTROL then wx.wxMOD_CONTROL = 0x02 end -if not wx.wxMOD_RAW_CONTROL then - wx.wxMOD_RAW_CONTROL = ide.osname == 'Macintosh' and 0x10 or wx.wxMOD_CONTROL -end --- ArchLinux running 2.8.12.2 doesn't have wx.wxMOD_SHIFT defined -if not wx.wxMOD_SHIFT then wx.wxMOD_SHIFT = 0x04 end --- wxDIR_NO_FOLLOW is missing in wxlua 2.8.12 as well -if not wx.wxDIR_NO_FOLLOW then wx.wxDIR_NO_FOLLOW = 0x10 end -if not wxaui.wxAUI_TB_PLAIN_BACKGROUND then wxaui.wxAUI_TB_PLAIN_BACKGROUND = 2^8 end - -if not setfenv then -- Lua 5.2 - -- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html - -- this assumes f is a function - local function findenv(f) - local level = 1 - repeat - local name, value = debug.getupvalue(f, level) - if name == '_ENV' then return level, value end - level = level + 1 - until name == nil - return nil end - getfenv = function (f) return(select(2, findenv(f)) or _G) end - setfenv = function (f, t) - local level = findenv(f) - if level then debug.setupvalue(f, level, t) end - return f end -end - -dofile "src/version.lua" - -for _, file in ipairs({"proto", "ids", "style", "keymap", "toolbar"}) do - dofile("src/editor/"..file..".lua") -end - -ide.config.styles = StylesGetDefault() -ide.config.stylesoutshell = StylesGetDefault() - -local function setLuaPaths(mainpath, osname) - -- use LUA_DEV to setup paths for Lua for Windows modules if installed - local luadev = osname == "Windows" and os.getenv('LUA_DEV') - if luadev and not wx.wxDirExists(luadev) then luadev = nil end - local luadev_path = (luadev - and ('LUA_DEV/?.lua;LUA_DEV/?/init.lua;LUA_DEV/lua/?.lua;LUA_DEV/lua/?/init.lua') - :gsub('LUA_DEV', (luadev:gsub('[\\/]$',''))) - or nil) - local luadev_cpath = (luadev - and ('LUA_DEV/?.dll;LUA_DEV/?51.dll;LUA_DEV/clibs/?.dll;LUA_DEV/clibs/?51.dll') - :gsub('LUA_DEV', (luadev:gsub('[\\/]$',''))) - or nil) - - if luadev then - local path, clibs = os.getenv('PATH'), luadev:gsub('[\\/]$','')..'\\clibs' - if not path:find(clibs, 1, true) then wx.wxSetEnv('PATH', path..';'..clibs) end - end - - -- (luaconf.h) in Windows, any exclamation mark ('!') in the path is replaced - -- by the path of the directory of the executable file of the current process. - -- this effectively prevents any path with an exclamation mark from working. - -- if the path has an excamation mark, allow Lua to expand it as this - -- expansion happens only once. - if osname == "Windows" and mainpath:find('%!') then mainpath = "!/../" end - - -- if LUA_PATH or LUA_CPATH is not specified, then add ;; - -- ;; will be replaced with the default (c)path by the Lua interpreter - wx.wxSetEnv("LUA_PATH", - (os.getenv("LUA_PATH") or ';') .. ';' - .. "./?.lua;./?/init.lua;./lua/?.lua;./lua/?/init.lua" .. ';' - .. mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua;" - .. mainpath.."lualibs/?/?/init.lua;"..mainpath.."lualibs/?/init.lua" - .. (luadev_path and (';' .. luadev_path) or '')) - - ide.osclibs = -- keep the list to use for other Lua versions - osname == "Windows" and mainpath.."bin/?.dll;"..mainpath.."bin/clibs/?.dll" or - osname == "Macintosh" and mainpath.."bin/lib?.dylib;"..mainpath.."bin/clibs/?.dylib" or - osname == "Unix" and mainpath..("bin/linux/%s/lib?.so;"):format(arch) - ..mainpath..("bin/linux/%s/clibs/?.so"):format(arch) or - assert(false, "Unexpected OS name") - - wx.wxSetEnv("LUA_CPATH", - (os.getenv("LUA_CPATH") or ';') .. ';' .. ide.osclibs - .. (luadev_cpath and (';' .. luadev_cpath) or '')) - - -- on some OSX versions, PATH is sanitized to not include even /usr/local/bin; add it - if osname == "Macintosh" then - local ok, path = wx.wxGetEnv("PATH") - if ok then wx.wxSetEnv("PATH", (#path > 0 and path..":" or "").."/usr/local/bin") end - end -end - -ide.test.setLuaPaths = setLuaPaths - ---------------- --- process args -local filenames = {} -local configs = {} -do - local arg = {...} - -- application name is expected as the first argument - local fullPath = arg[1] or "zbstudio" - - ide.arg = arg - - -- on Windows use GetExecutablePath, which is Unicode friendly, - -- whereas wxGetCwd() is not (at least in wxlua 2.8.12.2). - -- some wxlua version on windows report wx.dll instead of *.exe. - local exepath = wx.wxStandardPaths.Get():GetExecutablePath() - if ide.osname == "Windows" and exepath:find("%.exe$") then - fullPath = exepath - elseif not wx.wxIsAbsolutePath(fullPath) then - fullPath = wx.wxGetCwd().."/"..fullPath - end - - ide.editorFilename = fullPath - ide.appname = fullPath:match("([%w_-%.]+)$"):gsub("%.[^%.]*$","") - assert(ide.appname, "no application path defined") - - for index = 2, #arg do - if (arg[index] == "-cfg" and index+1 <= #arg) then - table.insert(configs,arg[index+1]) - elseif arg[index-1] ~= "-cfg" - -- on OSX command line includes -psn... parameter, don't include these - and (ide.osname ~= 'Macintosh' or not arg[index]:find("^-psn")) then - table.insert(filenames,arg[index]) - end - end - - setLuaPaths(GetPathWithSep(ide.editorFilename), ide.osname) -end - ----------------------- --- process application - -ide.app = dofile(ide.appname.."/app.lua") -local app = assert(ide.app) - -local function loadToTab(filter, folder, tab, recursive, proto) - if filter and type(filter) ~= 'function' then - filter = app.loadfilters[filter] or nil - end - for _, file in ipairs(FileSysGetRecursive(folder, recursive, "*.lua")) do - if not filter or filter(file) then - LoadLuaFileExt(tab, file, proto) - end - end - return tab -end - -local function loadInterpreters(filter) - loadToTab(filter or "interpreters", "interpreters", ide.interpreters, false, - ide.proto.Interpreter) -end - --- load tools -local function loadTools(filter) - loadToTab(filter or "tools", "tools", ide.tools, false) -end - --- load packages -local function processPackages(packages) - -- check dependencies and assign file names to each package - local skip = {} - for fname, package in pairs(packages) do - if type(package.dependencies) == 'table' - and package.dependencies.osname - and not package.dependencies.osname:find(ide.osname, 1, true) then - ide:Print(("Package '%s' not loaded: requires %s platform, but you are running %s.") - :format(fname, package.dependencies.osname, ide.osname)) - skip[fname] = true - end - - local needsversion = tonumber(package.dependencies) - or type(package.dependencies) == 'table' and tonumber(package.dependencies[1]) - or -1 - local isversion = tonumber(ide.VERSION) - if isversion and needsversion > isversion then - ide:Print(("Package '%s' not loaded: requires version %s, but you are running version %s.") - :format(fname, needsversion, ide.VERSION)) - skip[fname] = true - end - package.fname = fname - end - - for fname, package in pairs(packages) do - if not skip[fname] then ide.packages[fname] = package end - end -end - -function UpdateSpecs() - for _, spec in pairs(ide.specs) do - spec.sep = spec.sep or "\1" -- default separator doesn't match anything - spec.iscomment = {} - spec.iskeyword0 = {} - spec.isstring = {} - if (spec.lexerstyleconvert) then - if (spec.lexerstyleconvert.comment) then - for _, s in pairs(spec.lexerstyleconvert.comment) do - spec.iscomment[s] = true - end - end - if (spec.lexerstyleconvert.keywords0) then - for _, s in pairs(spec.lexerstyleconvert.keywords0) do - spec.iskeyword0[s] = true - end - end - if (spec.lexerstyleconvert.stringtxt) then - for _, s in pairs(spec.lexerstyleconvert.stringtxt) do - spec.isstring[s] = true - end - end - end - end -end - --- load specs -local function loadSpecs(filter) - loadToTab(filter or "specs", "spec", ide.specs, true) - UpdateSpecs() -end - -function GetIDEString(keyword, default) - return app.stringtable[keyword] or default or keyword -end - ----------------------- --- process config - --- set ide.config environment -do - ide.configs = { - system = MergeFullPath("cfg", "user.lua"), - user = ide.oshome and MergeFullPath(ide.oshome, "."..ide.appname.."/user.lua"), - } - ide.configqueue = {} - - local num = 0 - local package = setmetatable({}, { - __index = function(_,k) return package[k] end, - __newindex = function(_,k,v) package[k] = v end, - __call = function(_,p) - -- package can be defined inline, like "package {...}" - if type(p) == 'table' then - num = num + 1 - local name = 'config'..num..'package' - ide.packages[name] = setmetatable(p, ide.proto.Plugin) - -- package can be included as "package 'file.lua'" or "package 'folder/'" - elseif type(p) == 'string' then - local config = ide.configqueue[#ide.configqueue] - local pkg - for _, packagepath in ipairs({'.', 'packages/', '../packages/'}) do - local p = config and MergeFullPath(config.."/../"..packagepath, p) - pkg = wx.wxDirExists(p) and loadToTab(nil, p, {}, false, ide.proto.Plugin) - or wx.wxFileExists(p) and LoadLuaFileExt({}, p, ide.proto.Plugin) - or wx.wxFileExists(p..".lua") and LoadLuaFileExt({}, p..".lua", ide.proto.Plugin) - if pkg then - processPackages(pkg) - break - end - end - if not pkg then ide:Print(("Can't find '%s' to load package from."):format(p)) end - else - ide:Print(("Can't load package based on parameter of type '%s'."):format(type(p))) - end - end, - }) - - local includes = {} - local include = function(c) - if c then - for _, config in ipairs({ide.configqueue[#ide.configqueue], ide.configs.user, ide.configs.system}) do - local p = config and MergeFullPath(config.."/../", c) - includes[p] = (includes[p] or 0) + 1 - if includes[p] > 1 or LoadLuaConfig(p) or LoadLuaConfig(p..".lua") then return end - includes[p] = includes[p] - 1 - end - ide:Print(("Can't find configuration file '%s' to process."):format(c)) - end - end - - setmetatable(ide.config, { - __index = setmetatable({ - load = {interpreters = loadInterpreters, specs = loadSpecs, tools = loadTools}, - package = package, - include = include, - }, {__index = _G or _ENV}) - }) -end - -LoadLuaConfig(ide.appname.."/config.lua") - -ide.editorApp:SetAppName(GetIDEString("settingsapp")) - --- check if the .ini file needs to be migrated on Windows -if ide.osname == 'Windows' and ide.wxver >= "2.9.5" then - -- Windows used to have local ini file kept in wx.wxGetHomeDir (before 2.9), - -- but since 2.9 it's in GetUserConfigDir(), so migrate it. - local ini = ide.editorApp:GetAppName() .. ".ini" - local old = wx.wxFileName(wx.wxGetHomeDir(), ini) - local new = wx.wxFileName(wx.wxStandardPaths.Get():GetUserConfigDir(), ini) - if old:FileExists() and not new:FileExists() then - FileCopy(old:GetFullPath(), new:GetFullPath()) - ide:Print(("Migrated configuration file from '%s' to '%s'.") - :format(old:GetFullPath(), new:GetFullPath())) - end -end - ----------------------- --- process plugins - -if app.preinit then app.preinit() end - -loadInterpreters() -loadSpecs() -loadTools() - -do - -- process configs - LoadLuaConfig(ide.configs.system) - LoadLuaConfig(ide.configs.user) - - -- process all other configs (if any) - for _, v in ipairs(configs) do LoadLuaConfig(v, true) end - configs = nil - - -- check and apply default styles in case a user resets styles in the config - for _, styles in ipairs({"styles", "stylesoutshell"}) do - if not ide.config[styles] then - ide:Print(("Ignored incorrect value of '%s' setting in the configuration file") - :format(styles)) - ide.config[styles] = StylesGetDefault() - end - end - - local sep = GetPathSeparator() - if ide.config.language then - LoadLuaFileExt(ide.config.messages, "cfg"..sep.."i18n"..sep..ide.config.language..".lua") - end - -- always load 'en' as it's requires as a fallback for pluralization - if ide.config.language ~= 'en' then - LoadLuaFileExt(ide.config.messages, "cfg"..sep.."i18n"..sep.."en.lua") - end -end - -processPackages(loadToTab(nil, "packages", {}, false, ide.proto.Plugin)) -if ide.oshome then - local userpackages = MergeFullPath(ide.oshome, "."..ide.appname.."/packages") - if wx.wxDirExists(userpackages) then - processPackages(loadToTab(nil, userpackages, {}, false, ide.proto.Plugin)) - end -end - ---------------- --- Load App - -for _, file in ipairs({ - "settings", "singleinstance", "iofilters", "package", "markup", - "gui", "filetree", "output", "debugger", "outline", "commandbar", - "editor", "findreplace", "commands", "autocomplete", "shellbox", "markers", - "menu_file", "menu_edit", "menu_search", - "menu_view", "menu_project", "menu_tools", "menu_help", - "print", "inspect" }) do - dofile("src/editor/"..file..".lua") -end - --- register all the plugins -PackageEventHandle("onRegister") - --- initialization that was delayed until configs processed and packages loaded -ProjectUpdateInterpreters() - --- load rest of settings -SettingsRestoreFramePosition(ide.frame, "MainFrame") -SettingsRestoreView() -SettingsRestoreFileHistory(SetFileHistory) -SettingsRestoreEditorSettings() -SettingsRestoreProjectSession(FileTreeSetProjects) -SettingsRestoreFileSession(function(tabs, params) - if params and params.recovery - then return SetOpenTabs(params) - else return SetOpenFiles(tabs, params) end -end) - --- --------------------------------------------------------------------------- --- Load the filenames - -do - for _, filename in ipairs(filenames) do - if filename ~= "--" then - if wx.wxDirExists(filename) then - ProjectUpdateProjectDir(filename) - elseif not ActivateFile(filename) then - DisplayOutputLn(("Can't open file '%s': %s"):format(filename, wx.wxSysErrorMsg())) - end - end - end - if ide:GetEditorNotebook():GetPageCount() == 0 then NewFile() end -end - -if app.postinit then app.postinit() end - --- this is a workaround for a conflict between global shortcuts and local --- shortcuts (like F2) used in the file tree or a watch panel. --- because of several issues on OSX (as described in details in this thread: --- https://groups.google.com/d/msg/wx-dev/juJj_nxn-_Y/JErF1h24UFsJ), --- the workaround installs a global event handler that manually re-routes --- conflicting events when the current focus is on a proper object. --- non-conflicting shortcuts are handled through key-down events. -local remap = { - [ID_ADDWATCH] = ide:GetWatch(), - [ID_EDITWATCH] = ide:GetWatch(), - [ID_DELETEWATCH] = ide:GetWatch(), - [ID_RENAMEFILE] = ide:GetProjectTree(), - [ID_DELETEFILE] = ide:GetProjectTree(), -} - -local function rerouteMenuCommand(obj, id) - -- check if the conflicting shortcut is enabled: - -- (1) SetEnabled wasn't called or (2) Enabled was set to `true`. - local uievent = wx.wxUpdateUIEvent(id) - obj:ProcessEvent(uievent) - if not uievent:GetSetEnabled() or uievent:GetEnabled() then - obj:AddPendingEvent(wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, id)) - end -end - -local function remapkey(event) - local keycode = event:GetKeyCode() - local mod = event:GetModifiers() - for id, obj in pairs(remap) do - local focus = obj:FindFocus() - if focus and focus:GetId() == obj:GetId() then - local ae = wx.wxAcceleratorEntry(); ae:FromString(KSC(id)) - if ae:GetFlags() == mod and ae:GetKeyCode() == keycode then - rerouteMenuCommand(obj, id) - return - end - end - end - event:Skip() -end -ide:GetWatch():Connect(wx.wxEVT_KEY_DOWN, remapkey) -ide:GetProjectTree():Connect(wx.wxEVT_KEY_DOWN, remapkey) - -local function resolveConflict(localid, globalid) - return function(event) - local shortcut = ide.config.keymap[localid] - for id, obj in pairs(remap) do - if ide.config.keymap[id]:lower() == shortcut:lower() then - local focus = obj:FindFocus() - if focus and focus:GetId() == obj:GetId() then - obj:AddPendingEvent(wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, id)) - return - -- also need to check for children of objects - -- to avoid re-triggering events when labels are being edited - elseif focus and focus:GetParent():GetId() == obj:GetId() then - return - end - end - end - rerouteMenuCommand(ide.frame, globalid) - end -end - -local at = {} -for lid in pairs(remap) do - local shortcut = ide.config.keymap[lid] - -- find a (potential) conflict for this shortcut (if any) - for gid, ksc in pairs(ide.config.keymap) do - -- if the same shortcut is used elsewhere (not one of IDs being checked) - if shortcut:lower() == ksc:lower() and not remap[gid] then - local fakeid = NewID() - ide.frame:Connect(fakeid, wx.wxEVT_COMMAND_MENU_SELECTED, - resolveConflict(lid, gid)) - - local ae = wx.wxAcceleratorEntry(); ae:FromString(ksc) - table.insert(at, wx.wxAcceleratorEntry(ae:GetFlags(), ae:GetKeyCode(), fakeid)) - end - end -end - -if ide.osname == 'Macintosh' then - table.insert(at, wx.wxAcceleratorEntry(wx.wxACCEL_CTRL, ('M'):byte(), ID_VIEWMINIMIZE)) -end -ide.frame:SetAcceleratorTable(wx.wxAcceleratorTable(at)) - --- only set menu bar *after* postinit handler as it may include adding --- app-specific menus (Help/About), which are not recognized by MacOS --- as special items unless SetMenuBar is done after menus are populated. -ide.frame:SetMenuBar(ide.frame.menuBar) - -ide:Print() -- flush pending output (if any) - -PackageEventHandle("onAppLoad") - --- The status bar content is drawn incorrectly if it is shown --- after being initially hidden. --- Show the statusbar and hide it after showing the frame, which fixes the issue. -local statusbarfix = ide.osname == 'Windows' and not ide.frame:GetStatusBar():IsShown() -if statusbarfix then ide.frame:GetStatusBar():Show(true) end - -ide.frame:Show(true) - -if statusbarfix then ide.frame:GetStatusBar():Show(false) end - --- somehow having wxAuiToolbar "steals" the focus from the editor on OSX; --- have to set the focus implicitly on the current editor (if any) -if ide.osname == 'Macintosh' then - local editor = GetEditor() - if editor then editor:SetFocus() end -end - -wx.wxGetApp():MainLoop() - --- There are several reasons for this call: --- (1) to fix a crash on OSX when closing with debugging in progress. --- (2) to fix a crash on Linux 32/64bit during GC cleanup in wxlua --- after an external process has been started from the IDE. --- (3) to fix exit on Windows when started as "bin\lua src\main.lua". -os.exit() diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/util.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/util.lua deleted file mode 100644 index ad4cbe3..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/util.lua +++ /dev/null @@ -1,645 +0,0 @@ --- Copyright 2011-15 Paul Kulchenko, ZeroBrane LLC --- authors: Lomtik Software (J. Winwood & John Labenski) --- Luxinia Dev (Eike Decker & Christoph Kubisch) --- David Manura ---------------------------------------------------------- - --- Equivalent to C's "cond ? a : b", all terms will be evaluated -function iff(cond, a, b) if cond then return a else return b end end - -function EscapeMagic(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end - -function GetPathSeparator() - return string.char(wx.wxFileName.GetPathSeparator()) -end - -do - local sep = GetPathSeparator() - function IsDirectory(dir) return dir:find(sep.."$") end -end - -function StripCommentsC(tx) - local out = "" - local lastc = "" - local skip - local skipline - local skipmulti - local tx = string.gsub(tx, "\r\n", "\n") - for c in tx:gmatch(".") do - local oc = c - local tu = lastc..c - skip = c == '/' - - if ( not (skipmulti or skipline)) then - if (tu == "//") then - skipline = true - elseif (tu == "/*") then - skipmulti = true - c = "" - elseif (lastc == '/') then - oc = tu - end - elseif (skipmulti and tu == "*/") then - skipmulti = false - c = "" - elseif (skipline and lastc == "\n") then - out = out.."\n" - skipline = false - end - - lastc = c - if (not (skip or skipline or skipmulti)) then - out = out..oc - end - end - - return out..lastc -end - --- http://lua-users.org/wiki/EnhancedFileLines -function FileLines(f) - local CHUNK_SIZE = 1024 - local buffer = "" - local pos_beg = 1 - return function() - local pos, chars - while 1 do - pos, chars = buffer:match('()([\r\n].)', pos_beg) - if pos or not f then - break - elseif f then - local chunk = f:read(CHUNK_SIZE) - if chunk then - buffer = buffer:sub(pos_beg) .. chunk - pos_beg = 1 - else - f = nil - end - end - end - if not pos then - pos = #buffer - elseif chars == '\r\n' then - pos = pos + 1 - end - local line = buffer:sub(pos_beg, pos) - pos_beg = pos + 1 - if #line > 0 then - return line - end - end -end - -function PrependStringToArray(t, s, maxstrings, issame) - if string.len(s) == 0 then return end - for i = #t, 1, -1 do - local v = t[i] - if v == s or issame and issame(s, v) then - table.remove(t, i) -- remove old copy - -- don't break here in case there are multiple copies to remove - end - end - table.insert(t, 1, s) - if #t > (maxstrings or 15) then table.remove(t, #t) end -- keep reasonable length -end - -function GetFileModTime(filePath) - if filePath and #filePath > 0 then - local fn = wx.wxFileName(filePath) - if fn:FileExists() then - return fn:GetModificationTime() - end - end - - return nil -end - -function GetFileExt(filePath) - local match = filePath and filePath:gsub("%s+$",""):match("%.([^./\\]*)$") - return match and match:lower() or '' -end - -function GetFileName(filePath) - return filePath and filePath:gsub("%s+$",""):match("([^/\\]*)$") or '' -end - -function IsLuaFile(filePath) - return filePath and (string.len(filePath) > 4) and - (string.lower(string.sub(filePath, -4)) == ".lua") -end - -function GetPathWithSep(wxfn) - if type(wxfn) == 'string' then wxfn = wx.wxFileName(wxfn) end - return wxfn:GetPath(bit.bor(wx.wxPATH_GET_VOLUME, wx.wxPATH_GET_SEPARATOR)) -end - -function FileDirHasContent(dir) - local f = wx.wxFindFirstFile(dir, wx.wxFILE + wx.wxDIR) - return #f>0 -end - -function FileSysGetRecursive(path, recursive, spec, opts) - local content = {} - local showhidden = ide.config and ide.config.showhiddenfiles - local sep = GetPathSeparator() - -- trip trailing separator and adjust the separator in the path - path = path:gsub("[\\/]$",""):gsub("[\\/]", sep) - local queue = {path} - local pathpatt = "^"..EscapeMagic(path)..sep.."?" - local optyield = (opts or {}).yield - local optfolder = (opts or {}).folder ~= false - local optsort = (opts or {}).sort ~= false - local optpath = (opts or {}).path ~= false - local optskipbinary = (opts or {}).skipbinary - local optondirectory = (opts or {}).ondirectory - - local function spec2list(spec, list) - -- return empty list if no spec is provided - if spec == nil or spec == "*" or spec == "*.*" then return {}, 0 end - -- accept "*.lua" and "*.txt,*.wlua" combinations - if type(spec) == 'table' then spec = table.concat(spec, ",") end - local masknum, list = 0, list or {} - for m in spec:gmatch("[^%s;,]+") do - m = m:gsub("[\\/]", sep) - if m:find("^%*%.%w+"..sep.."?$") then - list[m:sub(2)] = true - else - -- escape all special characters - -- and replace (escaped) ** with .* and (escaped) * with [^\//]* - table.insert(list, EscapeMagic(m) - :gsub("%%%*%%%*", ".*"):gsub("%%%*", "[^/\\]*").."$") - end - masknum = masknum + 1 - end - return list, masknum - end - - local inmasks, masknum = spec2list(spec) - if masknum >= 2 then spec = nil end - - local exmasks = spec2list(ide.config.excludelist or {}) - if optskipbinary then -- add any binary files to the list to skip - exmasks = spec2list(type(optskipbinary) == 'table' and optskipbinary - or ide.config.binarylist or {}, exmasks) - end - - local function ismatch(file, inmasks, exmasks) - -- convert extension 'foo' to '.foo', as need to distinguish file - -- from extension with the same name - local ext = '.'..GetFileExt(file) - -- check exclusions if needed - if exmasks[file] or exmasks[ext] then return false end - for _, mask in ipairs(exmasks) do - if file:find(mask) then return false end - end - - -- return true if none of the exclusions match and no inclusion list - if not inmasks or not next(inmasks) then return true end - - -- now check inclusions - if inmasks[file] or inmasks[ext] then return true end - for _, mask in ipairs(inmasks) do - if file:find(mask) then return true end - end - return false - end - - local function report(fname) - if optyield then return coroutine.yield(fname) end - table.insert(content, fname) - end - - local dir = wx.wxDir() - local function getDir(path) - dir:Open(path) - if not dir:IsOpened() then - if DisplayOutputLn and TR then - DisplayOutputLn(TR("Can't open '%s': %s"):format(path, wx.wxSysErrorMsg())) - end - return - end - - -- recursion is done in all folders if requested, - -- but only those folders that match the spec are returned - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - local found, file = dir:GetFirst("*", - wx.wxDIR_DIRS + ((showhidden == true or showhidden == wx.wxDIR_DIRS) and wx.wxDIR_HIDDEN or 0)) - while found do - local fname = path..sep..file - if optfolder and ismatch(fname..sep, inmasks, exmasks) then - report((optpath and fname or fname:gsub(pathpatt, ""))..sep) - end - - if recursive and ismatch(fname..sep, nil, exmasks) - and (not optondirectory or optondirectory(fname) ~= false) - -- check if this name already appears in the path earlier; - -- Skip the processing if it does as it could lead to infinite - -- recursion with circular references created by symlinks. - and select(2, fname:gsub(EscapeMagic(file..sep),'')) <= 2 then - table.insert(queue, fname) - end - found, file = dir:GetNext() - end - found, file = dir:GetFirst(spec or "*", - wx.wxDIR_FILES + ((showhidden == true or showhidden == wx.wxDIR_FILES) and wx.wxDIR_HIDDEN or 0)) - while found do - local fname = path..sep..file - if ismatch(fname, inmasks, exmasks) then - report(optpath and fname or fname:gsub(pathpatt, "")) - end - found, file = dir:GetNext() - end - end - while #queue > 0 do getDir(table.remove(queue)) end - - if optyield then return end - - if optsort then - local prefix = '\001' -- prefix to sort directories first - local shadow = {} - for _, v in ipairs(content) do - shadow[v] = (v:sub(-1) == sep and prefix or '')..v:lower() - end - table.sort(content, function(a,b) return shadow[a] < shadow[b] end) - end - - return content -end - -local normalflags = wx.wxPATH_NORM_ABSOLUTE + wx.wxPATH_NORM_DOTS + wx.wxPATH_NORM_TILDE -function GetFullPathIfExists(p, f) - if not p or not f then return end - local file = wx.wxFileName(f) - -- Normalize call is needed to make the case of p = '/abc/def' and - -- f = 'xyz/main.lua' work correctly. Normalize() returns true if done. - return (file:Normalize(normalflags, p) - and file:FileExists() - and file:GetFullPath() - or nil) -end - -function MergeFullPath(p, f) - if not p or not f then return end - local file = wx.wxFileName(f) - -- Normalize call is needed to make the case of p = '/abc/def' and - -- f = 'xyz/main.lua' work correctly. Normalize() returns true if done. - return (file:Normalize(normalflags, p) - and file:GetFullPath() - or nil) -end - -function FileWrite(file, content) - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - - if not wx.wxFileExists(file) - and not wx.wxFileName(file):Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL) then - return nil, wx.wxSysErrorMsg() - end - - local file = wx.wxFile(file, wx.wxFile.write) - if not file:IsOpened() then return nil, wx.wxSysErrorMsg() end - - local ok = file:Write(content, #content) == #content - file:Close() - return ok, not ok and wx.wxSysErrorMsg() or nil -end - -function FileSize(fname) - if not wx.wxFileExists(fname) then return end - local size = wx.wxFileSize(fname) - -- size can be returned as 0 for symlinks, so check with wxFile:Length(); - -- can't use wxFile:Length() as it's reported incorrectly for some non-seekable files - -- (see https://github.com/pkulchenko/ZeroBraneStudio/issues/458); - -- the combination of wxFileSize and wxFile:Length() should do the right thing. - if size == 0 then size = wx.wxFile(fname, wx.wxFile.read):Length() end - return size -end - -function FileRead(fname, length, callback) - -- on OSX "Open" dialog allows to open applications, which are folders - if wx.wxDirExists(fname) then return nil, "Can't read directory as file." end - - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - local file = wx.wxFile(fname, wx.wxFile.read) - if not file:IsOpened() then return nil, wx.wxSysErrorMsg() end - - if type(callback) == 'function' then - length = length or 8192 - local pos = 0 - while true do - local len, content = file:Read(length) - local res, msg = callback(content) -- may return `false` to signal to stop - if res == false then return false, msg or "Unknown error" end - if len < length then break end - pos = pos + len - file:Seek(pos) - end - return true, wx.wxSysErrorMsg() - end - - local _, content = file:Read(length or FileSize(fname)) - file:Close() - return content, wx.wxSysErrorMsg() -end - -function FileRemove(file) - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - return wx.wxRemoveFile(file), wx.wxSysErrorMsg() -end - -function FileRename(file1, file2) - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - return wx.wxRenameFile(file1, file2), wx.wxSysErrorMsg() -end - -function FileCopy(file1, file2) - local _ = wx.wxLogNull() -- disable error reporting; will report as needed - return wx.wxCopyFile(file1, file2), wx.wxSysErrorMsg() -end - -local ok, socket = pcall(require, "socket") -TimeGet = ok and socket.gettime or os.clock - -function IsBinary(text) return text:find("[^\7\8\9\10\12\13\27\32-\255]") and true or false end - -function pairsSorted(t, f) - local a = {} - for n in pairs(t) do table.insert(a, n) end - table.sort(a, f) - local i = 0 -- iterator variable - local iter = function () -- iterator function - i = i + 1 - if a[i] == nil then return nil - else return a[i], t[a[i]] - end - end - return iter -end - -function FixUTF8(s, repl) - local p, len, invalid = 1, #s, {} - while p <= len do - if s:find("^[%z\1-\127]", p) then p = p + 1 - elseif s:find("^[\194-\223][\128-\191]", p) then p = p + 2 - elseif s:find( "^\224[\160-\191][\128-\191]", p) - or s:find("^[\225-\236][\128-\191][\128-\191]", p) - or s:find( "^\237[\128-\159][\128-\191]", p) - or s:find("^[\238-\239][\128-\191][\128-\191]", p) then p = p + 3 - elseif s:find( "^\240[\144-\191][\128-\191][\128-\191]", p) - or s:find("^[\241-\243][\128-\191][\128-\191][\128-\191]", p) - or s:find( "^\244[\128-\143][\128-\191][\128-\191]", p) then p = p + 4 - else - if not repl then return end -- just signal invalid UTF8 string - local repl = type(repl) == 'function' and repl(s:sub(p,p)) or repl - s = s:sub(1, p-1)..repl..s:sub(p+1) - table.insert(invalid, p) - -- adjust position/length as the replacement may be longer than one char - p = p + #repl - len = len + #repl - 1 - end - end - return s, invalid -end - -function RequestAttention() - local frame = ide.frame - if not frame:IsActive() then - frame:RequestUserAttention() - if ide.osname == "Macintosh" then - local cmd = [[osascript -e 'tell application "%s" to activate']] - wx.wxExecute(cmd:format(ide.editorApp:GetAppName()), wx.wxEXEC_ASYNC) - elseif ide.osname == "Windows" then - if frame:IsIconized() then frame:Iconize(false) end - frame:Raise() -- raise the window - - local winapi = require 'winapi' - if winapi then - local pid = winapi.get_current_pid() - local wins = winapi.find_all_windows(function(w) - return w:get_process():get_pid() == pid - and w:get_class_name() == 'wxWindowNR' - end) - if wins and #wins > 0 then - -- found the window, now need to activate it: - -- send some input to the window and then - -- bring our window to foreground (doesn't work without some input) - -- send Attn key twice (down and up) - winapi.send_to_window(0xF6, false) - winapi.send_to_window(0xF6, true) - for _, w in ipairs(wins) do w:set_foreground() end - end - end - end - end -end - -function TR(msg, count) - local messages = ide.config.messages - local lang = ide.config.language - local counter = messages[lang] and messages[lang][0] - local message = messages[lang] and messages[lang][msg] - -- if there is count and no corresponding message, then - -- get the message from the (default) english language, - -- otherwise the message is not going to be pluralized properly - if count and (not message or type(message) == 'table' and not next(message)) then - message, counter = messages.en[msg], messages.en[0] - end - return count and counter and message and type(message) == 'table' - and message[counter(count)] or (type(message) == 'string' and message or msg) -end - --- wxwidgets 2.9.x may report the last folder twice (depending on how the --- user selects the folder), which makes the selected folder incorrect. --- check if the last segment is repeated and drop it. -function FixDir(path) - if wx.wxDirExists(path) then return path end - - local dir = wx.wxFileName.DirName(path) - local dirs = dir:GetDirs() - if #dirs > 1 and dirs[#dirs] == dirs[#dirs-1] then dir:RemoveLastDir() end - return dir:GetFullPath() -end - -function ShowLocation(fname) - local osxcmd = [[osascript -e 'tell application "Finder" to reveal POSIX file "%s"']] - .. [[ -e 'tell application "Finder" to activate']] - local wincmd = [[explorer /select,"%s"]] - local lnxcmd = [[xdg-open "%s"]] -- takes path, not a filename - local cmd = - ide.osname == "Windows" and wincmd:format(fname) or - ide.osname == "Macintosh" and osxcmd:format(fname) or - ide.osname == "Unix" and lnxcmd:format(wx.wxFileName(fname):GetPath()) - if cmd then wx.wxExecute(cmd, wx.wxEXEC_ASYNC) end -end - -function LoadLuaFileExt(tab, file, proto) - local cfgfn,err = loadfile(file) - if not cfgfn then - ide:Print(("Error while loading file: '%s'."):format(err)) - else - local name = file:match("([a-zA-Z_0-9%-]+)%.lua$") - if not name then return end - - -- check if os/arch matches to allow packages for different systems - local osvals = {windows = true, unix = true, macintosh = true} - local archvals = {x64 = true, x86 = true} - local os, arch = name:match("-(%w+)-?(%w*)") - if os and os:lower() ~= ide.osname:lower() and osvals[os:lower()] - or arch and #arch > 0 and arch:lower() ~= ide.osarch:lower() and archvals[arch:lower()] - then return end - if os and osvals[os:lower()] then name = name:gsub("-.*","") end - - local success, result = pcall(function()return cfgfn(assert(_G or _ENV))end) - if not success then - ide:Print(("Error while processing file: '%s'."):format(result)) - else - if (tab[name]) then - local out = tab[name] - for i,v in pairs(result) do - out[i] = v - end - else - tab[name] = proto and result and setmetatable(result, proto) or result - if tab[name] then tab[name].fpath = file end - end - end - end - return tab -end - -function LoadLuaConfig(filename,isstring) - if not filename then return end - -- skip those files that don't exist - if not isstring and not wx.wxFileExists(filename) then return end - -- if it's marked as command, but exists as a file, load it as a file - if isstring and wx.wxFileExists(filename) then isstring = false end - - local cfgfn, err, msg - if isstring - then msg, cfgfn, err = "string", loadstring(filename) - else msg, cfgfn, err = "file", loadfile(filename) end - - if not cfgfn then - ide:Print(("Error while loading configuration %s: '%s'."):format(msg, err)) - else - setfenv(cfgfn,ide.config) - table.insert(ide.configqueue, filename) - local _, err = pcall(function()cfgfn(assert(_G or _ENV))end) - table.remove(ide.configqueue) - if err then - ide:Print(("Error while processing configuration %s: '%s'."):format(msg, err)) - end - end - return true -end - -function LoadSafe(data) - local f, res = loadstring(data) - if not f then return f, res end - - local count = 0 - debug.sethook(function () - count = count + 1 - if count >= 3 then error("cannot call functions") end - end, "c") - local ok, res = pcall(f) - count = 0 - debug.sethook() - return ok, res -end - -local function isCtrlFocused(e) - local ctrl = e and e:FindFocus() - return ctrl and - (ctrl:GetId() == e:GetId() - or ide.osname == 'Macintosh' and - ctrl:GetParent():GetId() == e:GetId()) and ctrl or nil -end - -function GetEditorWithFocus(...) - -- need to distinguish GetEditorWithFocus() and GetEditorWithFocus(nil) - -- as the latter may happen when GetEditor() is passed and returns `nil` - if select('#', ...) > 0 then - local ed = ... - return isCtrlFocused(ed) and ed or nil - end - - local editor = GetEditor() - if isCtrlFocused(editor) then return editor end - - local nb = ide:GetOutputNotebook() - for p = 0, nb:GetPageCount()-1 do - local ctrl = nb:GetPage(p) - if ctrl:GetClassInfo():GetClassName() == "wxStyledTextCtrl" - and isCtrlFocused(ctrl) then - return ctrl:DynamicCast("wxStyledTextCtrl") - end - end - return nil -end - -function GenerateProgramFilesPath(exec, sep) - local env = os.getenv('ProgramFiles') - return - (env and env..'\\'..exec..sep or '').. - [[C:\Program Files\]]..exec..sep.. - [[D:\Program Files\]]..exec..sep.. - [[C:\Program Files (x86)\]]..exec..sep.. - [[D:\Program Files (x86)\]]..exec -end - ---[[ format placeholders - - %f -- full project name (project path) - - %s -- short project name (directory name) - - %i -- interpreter name - - %S -- file name - - %F -- file path - - %n -- line number - - %c -- line content - - %T -- application title - - %v -- application version - - %t -- current tab name ---]] -function ExpandPlaceholders(msg, ph) - ph = ph or {} - if type(msg) == 'function' then return msg(ph) end - local editor = ide:GetEditor() - local proj = ide:GetProject() or "" - local dirs = wx.wxFileName(proj):GetDirs() - local doc = editor and ide:GetDocument(editor) - local nb = ide:GetEditorNotebook() - local def = { - f = proj, - s = dirs[#dirs] or "", - i = ide:GetInterpreter():GetName() or "", - S = doc and doc:GetFileName() or "", - F = doc and doc:GetFilePath() or "", - n = editor and editor:GetCurrentLine()+1 or 0, - c = editor and editor:GetLineDyn(editor:GetCurrentLine()) or "", - T = GetIDEString("editor") or "", - v = ide.VERSION, - t = editor and nb:GetPageText(nb:GetPageIndex(editor)) or "", - } - return(msg:gsub('%%(%w)', function(p) return ph[p] or def[p] or '?' end)) -end - -function MergeSettings(localSettings, savedSettings) - for name in pairs(localSettings) do - if savedSettings[name] ~= nil - and type(savedSettings[name]) == type(localSettings[name]) then - if type(localSettings[name]) == 'table' - and next(localSettings[name]) ~= nil then - -- check every value in the table to make sure that it's possible - -- to add new keys to the table and they get correct default values - -- (even though that are absent in savedSettings) - for setting in pairs(localSettings[name]) do - if savedSettings[name][setting] ~= nil then - localSettings[name][setting] = savedSettings[name][setting] - end - end - else - localSettings[name] = savedSettings[name] - end - end - end -end diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/version.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/version.lua deleted file mode 100644 index fe3106b..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/src/version.lua +++ /dev/null @@ -1 +0,0 @@ -ide.VERSION = [[1.30]] diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cg.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cg.lua deleted file mode 100644 index 1dd4217..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cg.lua +++ /dev/null @@ -1,537 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local binpath = ide.config.path.cgbin or os.getenv("CG_BIN_PATH") -local cgprofile -local cgglsles - -return binpath and { - fninit = function(frame,menuBar) - cgprofile = ide.config.cgprofile or "gp5" - cgglsles = ide.config.cgglsles - - if (wx.wxFileName(binpath):IsRelative()) then - local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/") - binpath = editorDir..binpath - end - - local myMenu = wx.wxMenu{ - { ID "cg.profile.arb", "&ARB VP/FP", "ARB program profile", wx.wxITEM_CHECK }, - { ID "cg.profile.glsl", "ARB &GLSL", "ARB GLSL program profile", wx.wxITEM_CHECK }, - { ID "cg.profile.nv40", "NV VP/FP&40", "NV program sm3 profile", wx.wxITEM_CHECK }, - { ID "cg.profile.gp4", "NV &GP4", "NV program sm4 profile", wx.wxITEM_CHECK }, - { ID "cg.profile.gp5", "NV &GP5", "NV program sm5 profile", wx.wxITEM_CHECK }, - { ID "cg.profile.dx_2x", "DX SM&2_x", "DirectX sm2_x profile", wx.wxITEM_CHECK }, - { ID "cg.profile.dx_3", "DX SM&3_0", "DirectX sm3_0 profile", wx.wxITEM_CHECK }, - { ID "cg.profile.dx_4", "DX SM&4_0", "DirectX sm4_0 profile", wx.wxITEM_CHECK }, - { ID "cg.profile.dx_5", "DX SM&5_0", "DirectX sm5_0 profile", wx.wxITEM_CHECK }, - { }, - { ID "cg.compile.input", "&Custom Args", "when set a popup for custom compiler args will be envoked", wx.wxITEM_CHECK }, - { ID "cg.compile.gles", "GLSL-ES", "When GLSL file is source use GLSL-ES path", wx.wxITEM_CHECK }, - { }, - { ID "cg.compile.vertex", "Compile &Vertex", "Compile Vertex program (select entry word)" }, - { ID "cg.compile.fragment", "Compile &Fragment", "Compile Fragment program (select entry word)" }, - { ID "cg.compile.geometry", "Compile &Geometry", "Compile Geometry program (select entry word)" }, - { ID "cg.compile.tessctrl", "Compile T.Ctrl", "Compile T.Ctrl program (select entry word)" }, - { ID "cg.compile.tesseval", "Compile T.Eval", "Compile T.Eval program (select entry word)" }, - { ID "cg.compile.compute", "Compile Compute", "Compile Compute program (select entry word)" }, - { }, - { ID "cg.format.asm", "Annotate ASM", "indent and add comments to Cg ASM output" }, - { ID "cg.format.master", "Build from master", "Creates a new cg file from a master containing special include instrctions." }, - } - menuBar:Append(myMenu, "&Cg") - - local data = {} - data.customarg = false - data.custom = "" - data.profid = ID ("cg.profile."..cgprofile) - data.gles = cgglsles and true or false - data.domains = { - [ID "cg.compile.vertex"] = 1, - [ID "cg.compile.fragment"] = 2, - [ID "cg.compile.geometry"] = 3, - [ID "cg.compile.tessctrl"] = 4, - [ID "cg.compile.tesseval"] = 5, - [ID "cg.compile.compute"] = 6, - } - data.profiles = { - [ID "cg.profile.arb"] = {"arbvp1","arbfp1",false,false,false,false,ext=".glp", asm=true,}, - [ID "cg.profile.glsl"] = {"glslv","glslf","glslg",false,false,false,ext=".glsl"}, - [ID "cg.profile.nv40"] = {"vp40","fp40",false,false,false,false,ext=".glp",nvperf=true, asm=true,}, - [ID "cg.profile.gp4"] = {"gp4vp","gp4fp","gp4gp",false,false,false,ext=".glp",nvperf=true, asm=true,}, - [ID "cg.profile.gp5"] = {"gp5vp","gp5fp","gp5gp","gp5tcp","gp5tep","gp5cp",ext=".glp", asm=true,}, - [ID "cg.profile.dx_2x"] = {"vs_2_0","ps_2_x",false,false,false,false,ext=".txt"}, - [ID "cg.profile.dx_3"] = {"vs_3_0","ps_3_0",false,false,false,false,ext=".txt"}, - [ID "cg.profile.dx_4"] = {"vs_4_0","ps_4_0","gs_4_0",false,false,false,ext=".txt"}, - [ID "cg.profile.dx_5"] = {"vs_5_0","ps_5_0","gs_5_0","ds_5_0","hs_5_0",false,ext=".txt"}, - } - data.domaindefs = { - " -D_VERTEX_ ", - " -D_FRAGMENT_ ", - " -D_GEOMETRY_ ", - " -D_TESS_CONTROL_ ", - " -D_TESS_EVAL_ ", - " -D_COMPUTE_ ", - } - -- Profile related - menuBar:Check(data.profid, true) - - local function selectProfile (id) - for id,profile in pairs(data.profiles) do - menuBar:Check(id, false) - end - menuBar:Check(id, true) - data.profid = id - end - - menuBar:Check(ID "cg.compile.gles", data.gles) - - local function evSelectProfile (event) - local chose = event:GetId() - selectProfile(chose) - end - - for id,profile in pairs(data.profiles) do - frame:Connect(id,wx.wxEVT_COMMAND_MENU_SELECTED,evSelectProfile) - end - - -- check for NvPerf - local perfexe = "/NVShaderPerf.exe" - local fn = wx.wxFileName(binpath..perfexe) - local hasperf = fn:FileExists() - - -- master file generator - - local function buildFromMaster(filenamein, filenameout) - local path = GetPathWithSep(filenamein) - if (not filenameout) then - local name = filenamein:GetName() - name = name:match("(.+).master$") - if (not name) then return end - filenameout = path..name.."."..filenamein:GetExt() - end - - local masterfile = io.open(filenamein:GetFullPath(), "rb") - local outfile = io.open(filenameout, "wb") - - local function out(str) - --str = string.match(str," - return str - end - - local function handleInclude(fname,defs) - local defcnt = 0 - for i,v in pairs(defs) do - defcnt = defcnt + 1 - end - - local incfile = io.open(path..fname, "rb") - if (defcnt > 0) then - local write = nil - for line in FileLines(incfile) do - if (write) then - local cap = string.match(line,"#endif%s+//%s*([%w_]+)") - if (cap == write) then - outfile:write("//$"..write.." END$\n") - break - end - outfile:write(line) - else - local cap = string.match(line,"#ifdef%s+([%w_]+)") - if (cap and defs[cap]) then - write = cap - outfile:write("//$"..write.." BEGIN$\n") - end - end - end - else - for line in FileLines(incfile) do - outfile:write(line) - end - end - - incfile:close() - end - - DisplayOutput("Cg Master Generating...\n") - local master = nil - for line in FileLines(masterfile) do - local masterbegin = string.find(line,'//$MASTER-INCLUDE-BEGIN$',nil, true) - local masterend = string.find(line,'//$MASTER-INCLUDE-END$', nil, true) - if (masterbegin) then - master = {} - outfile:write(line) - elseif(masterend) then - master = nil - end - - if (master) then - local linein = " "..line - local defadd = string.match(linein,'[^/]#define ([_%w]+)') - local defrem = string.match(linein,'[^/]#undef ([_%w]+)') - if (defadd) then master[defadd] = true end - if (defrem) then master[defrem] = nil end - DisplayOutput(defadd,defrem, "\n") - - local incfile = string.match(linein,'[^/]#include "(.+)"') - if (incfile) then - handleInclude(incfile, master, "\n") - end - else - outfile:write(line) - end - end - DisplayOutput("Written:",filenameout,"\n") - outfile:close() - masterfile:close() - end - - local function beautifyAsm(tx) - local newtx = "" - local indent = 0 - local maxindent = 0 - local startindent = { - ["IF"]=true,["REP"]=true,["ELSE"]=true,["LOOP"]=true,["BB"]=true, - } - local endindent = { - ["ENDIF"]=true,["ENDREP"]=true,["ELSE"]=true,["ENDLOOP"]=true,["END"]=true,["RET"]=true, - } - - local function checknesting(str,tab) - local res - local chk = str:match("%s*(BB)%d+.*:") - chk = chk or str:match("%s*(%w+)") - res = chk and tab[chk] and chk - - return res - end - - local argregistry = {} - local argbuffersfixed = false - - local registercc - local registermem - - local function fixargbuffers() - if (argbuffersfixed) then return end - - local argnew = {} - for i,v in pairs(argregistry) do - local buf,bufstart = string.match(i,"buf(%d+)%[(%d+)%]") - if (buf and bufstart) then - bufstart = tonumber(bufstart)/16 - argnew["buf"..buf.."["..tostring(bufstart).."]"] = v - else - argnew[i] = v - end - end - argregistry = argnew - argbuffersfixed = true - end - - local function checkregistry(w) - local regsuccess = true - - local vtype,vname,sem,resource,pnum,pref = string.match(w,"#var ([_%w]+) ([%[%]%._%w]+) : ([^%:]*) : ([^%:]*) : ([^%:]*) : (%d*)") - local funcname,subroutine = string.match(w,"#function %d+ ([_%w]+)%((%d+)%)") - if (pref == "1") then - local descriptor = vtype.." "..vname - - -- check if resource is array - local resstart,rescnt = string.match(resource,"c%[(%d+)%], (%d+)") - resstart = tonumber(resstart) - rescnt = tonumber(rescnt) - - -- check if resource is buffer/buffer array - local buf,bufstart,bufcnt = string.match(resource,"buffer%[(%d+)%]%[(%d+)%],? ?(%d*)") - buf = tonumber(buf) - bufstart = tonumber(bufstart) - bufcnt = tonumber(bufcnt) - - -- check if texture - local texnum = string.match(resource,"texunit (%d+)") - - local argnames = {} - if (rescnt) then - for i=0,(rescnt-1) do - table.insert(argnames,"c["..tostring(resstart + i).."]") - end - elseif (texnum) then - table.insert(argnames,"texture["..tostring(texnum).."]") - table.insert(argnames,"texture"..tostring(texnum)) - elseif (buf) then - table.insert(argnames,"buf"..tostring(buf).."["..tostring(bufstart).."]") - else - table.insert(argnames,resource) - end - - for i,v in ipairs(argnames) do - argregistry[v] = descriptor - end - elseif (funcname and subroutine) then - argregistry["SUBROUTINENUM("..subroutine..")"] = "function "..funcname - elseif string.find(w,"BUFFER4") then - fixargbuffers() - elseif string.find(w,"TEMP") then - --TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; - --TEMP RC, HC; - --TEMP lmem[9]; - registercc = registercc or 0 - for i in string.gmatch(w,"C") do - registercc = registercc + 1 - end - registermem = tonumber(string.match(w,"lmem%[(%d+)%]")) - else - regsuccess = false - end - - return regsuccess - end - - local function checkargs(str) - local comment = "#" - local declared = {} - for i in string.gmatch(str,"([%[%]%(%)%w]+)") do - local descr = argregistry[i] - if (descr and not declared[i]) then - comment = comment.." "..i.." = "..descr - declared[i] = true - end - end - - return comment ~= "#" and comment - end - - local registerlevels = {{}} - local function checkregisters(str,indent) - if (indent < 0) then return end - local cur = registerlevels[indent+1] - for i in string.gmatch(str,"R(%d+)") do - cur[i] = true - end - end - - local function clearregisters(indent) - registerlevels[math.max(0,indent)+1] = {} - end - - local function outputregisters(indent) - if (indent < 0) then return "" end - local tab = registerlevels[indent+1] - local out = {} - for i,v in pairs(tab) do - table.insert(out,i) - end - table.sort(out) - local cnt = #out - if (cnt < 1) then return "" end - - local str = string.rep(" ",indent).."# "..tostring(cnt).." R used: " - for i,v in ipairs(out) do - str = str..tostring(v)..((i==cnt) and "" or ", ") - end - return str.."\n" - end - - -- check declarations - local lastline = "" - for w in string.gmatch(tx, "[^\n]*\n") do - if (not checkregistry(w)) then - - if (checknesting(w,endindent)) then - newtx = newtx..outputregisters(indent) - if (indent == 0) then clearregisters(indent) end - indent = math.max(0,indent - 1) - end - - local firstchar = string.sub(w,1,1) - local indentstr = (firstchar ~= " " and firstchar ~= "\t" and string.rep(" ",indent) or "") - local linestr = indentstr..w - local argcomment = (firstchar ~= "#") and checkargs(w) - - checkregisters(w,indent) - - newtx = newtx..(argcomment and (indentstr..argcomment.."\n") or "") - newtx = newtx..linestr - - if (checknesting(w,startindent)) then - indent = indent + 1 - maxindent = math.max(maxindent,indent) - clearregisters(indent) - end - else - newtx = newtx..w - end - lastline = w - end - - local registers = tonumber(string.match(lastline, "(%d+) R%-regs")) or 0 - registermem = registermem or 0 - registercc = registercc or 0 - local stats = "# "..tostring(registercc).." C-regs, "..tostring(registermem).." L-regs\n" - stats = stats.."# "..tostring(registercc + registermem + registers).." maximum registers\n" - stats = stats.."# "..maxindent.." maximum nesting level\n" - newtx = newtx..stats - - return newtx,lastline..stats - end - - local function beautifyAsmFile(filePath) - local file_text = "" - local statlines = "" - local handle = io.open(filePath, "rb") - if handle then - file_text = handle:read("*a") - file_text,statlines = beautifyAsm(file_text) - handle:close() - end - - if (file_text == "") then return end - - local handle = io.open(filePath, "wb") - if handle then - handle:write(file_text) - handle:close() - end - return statlines - end - - -- Compile Arg - frame:Connect(ID "cg.compile.input",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.customarg = event:IsChecked() - end) - - frame:Connect(ID "cg.compile.gles",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.gles = event:IsChecked() - end) - -- Compile - local function evCompile(event) - local filename,info = GetEditorFileAndCurInfo() - local editor = GetEditor() - local glsl = editor and editor.spec and editor.spec.apitype and editor.spec.apitype == "glsl" - local entryname = (glsl and "main" or info.selword) - - if (not (filename and entryname and binpath)) then - DisplayOutput("Error: Cg Compile: Insufficient parameters (nofile / not selected entry function!\n") - return - end - - local domain = data.domains[event:GetId()] - local profile = data.profiles[data.profid] - if (not profile[domain]) then return end - - -- popup for custom input - data.custom = data.customarg and wx.wxGetTextFromUser("Compiler Args","Cg",data.custom) or data.custom - local args = data.customarg and data.custom or "" - args = args:len() > 0 and args or nil - - local fullname = filename:GetFullPath() - local outname = fullname.."."..entryname.."^" - outname = args and outname..args:gsub("%s*[%-%/]",";-")..";^" or outname - outname = outname..profile[domain]..profile.ext - outname = '"'..outname..'"' - - local cmdglsl = data.gles and "-ogles -glslWerror -DGL_ES" or "-oglsl -glslWerror -po PaBO2 " - local cmdline = ' "'..fullname..'" -profile '..profile[domain].." " - cmdline = glsl and cmdline..cmdglsl or cmdline - cmdline = glsl and (data.profid == (ID "cg.profile.gp5")) and cmdline.."-po NV_shader_atomic_float -po NV_bindless_texture " or cmdline - cmdline = args and cmdline..args.." " or cmdline - cmdline = cmdline..data.domaindefs[domain] - cmdline = cmdline.."-o "..outname.." " - cmdline = cmdline.."-entry "..entryname - - cmdline = binpath.."/cgc.exe"..cmdline - - local function nvperfcallback(str) - local pixels = string.match(str,"([,%d]+) pixels/s") - pixels = pixels and string.gsub(pixels,",","") - pixels = tonumber(pixels) - local function tostr(num) - return string.format("%.2f",num) - end - - -- delete .cgbin file - local binname,ext = fullname:match("(.*)%.([a-zA-Z_0-9]+)$") - binname = binname..".cgbin" - wx.wxRemoveFile(binname) - - if (pixels ~= nil) then - local str = string.match(str,("(.* pixels/s)")) - local info = "1920x1080: "..tostr(pixels/(1920*1080)).." Hz\n" - info = info.."1280x1024: "..tostr(pixels/(1280*1024)).." Hz\n" - str = (str.."\n"..info) - return str - else - return str.."\n" - end - end - - local function compilecallback(str) - local postfunc - -- check for errors, if none, launch nvperf - -- and indentation - if (string.find(str," 0 errors.")) then - postfunc = function() - -- beautify asm - if (profile.asm) then - local statlines = beautifyAsmFile(outname:sub(2,-2)) - DisplayOutput(statlines) - end - - -- optionally run perf process - local cgperfgpu = ide.config.cgperfgpu or "G80" - local profiletypes = { - ["G70"] = {}, - ["G80"] = { - ["vp40"] = " -profile vp40", - ["fp40"] = " -profile fp40"}, - } - if (hasperf and (not glsl) and profile.nvperf and (domain == 1 or domain == 2) - and profiletypes[cgperfgpu]) - then - local domaintypes = {"cg_vp","cg_fp",} - local cmdline = " -gpu "..cgperfgpu.." -type "..domaintypes[domain] - cmdline = cmdline.." -function "..info.selword - cmdline = cmdline..(profiletypes[cgperfgpu][profile[domain]] or "") - cmdline = cmdline..' "'..fullname..'"' - - cmdline = binpath..perfexe..cmdline - CommandLineRun(cmdline,nil,true,nil,nvperfcallback) - end - end - end - - return str,postfunc - end - - -- run compiler process - CommandLineRun(cmdline,nil,true,nil,compilecallback) - - end - - frame:Connect(ID "cg.compile.vertex",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "cg.compile.fragment",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "cg.compile.geometry",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "cg.compile.tessctrl",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "cg.compile.tesseval",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "cg.compile.compute",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - - -- indent asm - frame:Connect(ID "cg.format.asm", wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - local curedit = GetEditor() - local newtx = beautifyAsm( curedit:GetText() ) - - curedit:SetText(newtx) - end) - - -- master file - frame:Connect(ID "cg.format.master", wx.wxEVT_COMMAND_MENU_SELECTED, - function(even) - local filename,info = GetEditorFileAndCurInfo() - buildFromMaster(filename) - end) - end, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/clcc.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/clcc.lua deleted file mode 100644 index f4082f2..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/clcc.lua +++ /dev/null @@ -1,67 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local binpath = ide.config.path.clccbin or os.getenv("CLCC_BIN_PATH") - -return binpath and { - fninit = function(frame,menuBar) - - if (wx.wxFileName(binpath):IsRelative()) then - local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/") - binpath = editorDir..binpath - end - - local myMenu = wx.wxMenu{ - { ID "cl.allplatforms", "&All", "Compiled with all available platforms (otherwise only first)", wx.wxITEM_CHECK }, - { ID "cl.output", "&Output", "Generates output files", wx.wxITEM_CHECK }, - { ID "cl.info", "&Info", "Prints Info", wx.wxITEM_CHECK }, - { }, - { ID "cl.compile", "&Compile", "Compile Kernels in File" }, - } - menuBar:Append(myMenu, "&OpenCL") - - local data = { - allplatforms = false, - output = false, - info = false, - } - - -- Compile Arg - frame:Connect(ID "cl.allplatforms",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.allplatforms = event:IsChecked() - end) - frame:Connect(ID "cl.output",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.output = event:IsChecked() - end) - frame:Connect(ID "cl.info",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.info = event:IsChecked() - end) - -- Compile - local function evCompile(event) - local filename,info = GetEditorFileAndCurInfo() - local editor = GetEditor() - - if (not (filename)) then - DisplayOutput("Error: OpenCL Compile: Insufficient parameters (nofile)!\n") - return - end - - local fullname = filename:GetFullPath() - local cmdline = " " - cmdline = cmdline..(data.allplatforms and "--platform -1 " or "") - cmdline = cmdline..(data.info and "--info " or "") - cmdline = cmdline..(data.output and "--output " or "") - cmdline = cmdline..'"'..fullname..'"' - - cmdline = binpath.."/clcc.exe"..cmdline - - -- run compiler process - CommandLineRun(cmdline,nil,true,nil,nil) - end - - frame:Connect(ID "cl.compile",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - end, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cstringify.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cstringify.lua deleted file mode 100644 index a650a77..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/cstringify.lua +++ /dev/null @@ -1,21 +0,0 @@ -local function cstringify() - local editor = GetEditor() - if (not editor) then end - local tx = editor:GetText() - local new = "" - for l in tx:gmatch("([^\r\n]*)([\r]?[\n]?)") do - l = l:gsub('\\','\\\\') - l = l:gsub('"','\\"') - new = new..'"'..l..'\\n"'.."\n" - end - -- replace text - editor:SetText(new) -end - -return { - exec = { - name = "stringify to C", - description = "stringifys the content for use in C", - fn = cstringify, - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/dx.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/dx.lua deleted file mode 100644 index 1753e0e..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/dx.lua +++ /dev/null @@ -1,157 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local binpath = ide.config.path.fxcbin or (os.getenv("DXSDK_DIR") and os.getenv("DXSDK_DIR").."/Utilities/bin/x86/") -local dxprofile - -return binpath and { - fninit = function(frame,menuBar) - dxprofile = ide.config.dxprofile or "dx_5" - - if (wx.wxFileName(binpath):IsRelative()) then - local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/") - binpath = editorDir..binpath - end - - local myMenu = wx.wxMenu{ - { ID "dx.profile.dx_2x", "DX SM&2_x", "DirectX sm2_x profile", wx.wxITEM_CHECK }, - { ID "dx.profile.dx_3", "DX SM&3_0", "DirectX sm3_0 profile", wx.wxITEM_CHECK }, - { ID "dx.profile.dx_4", "DX SM&4_0", "DirectX sm4_0 profile", wx.wxITEM_CHECK }, - { ID "dx.profile.dx_5", "DX SM&5_0", "DirectX sm5_0 profile", wx.wxITEM_CHECK }, - { }, - { ID "dx.compile.input", "Custom &Args", "when set a popup for custom compiler args will be envoked", wx.wxITEM_CHECK }, - { ID "dx.compile.binary", "&Binary", "when set compiles binary output", wx.wxITEM_CHECK }, - { ID "dx.compile.legacy", "&Legacy", "when set compiles in legacy mode", wx.wxITEM_CHECK }, - { ID "dx.compile.backwards", "Backwards Compatibility", "when set compiles in backwards compatibility mode", wx.wxITEM_CHECK }, - { }, - { ID "dx.compile.vertex", "Compile &Vertex", "Compile Vertex shader (select entry word)" }, - { ID "dx.compile.fragment", "Compile &Fragment", "Compile pixel shader (select entry word)" }, - { ID "dx.compile.geometry", "Compile &Geometry", "Compile Geometry shader (select entry word)" }, - { ID "dx.compile.domain", "Compile &Domain", "Compile Domain shader (select entry word)" }, - { ID "dx.compile.hull", "Compile &Hull", "Compile Hull shader (select entry word)" }, - { ID "dx.compile.compute", "Compile &Compute", "Compile Compute shader (select entry word)" }, - { ID "dx.compile.effects", "Compile &Effects", "Compile all effects in shader" }, - } - menuBar:Append(myMenu, "&Dx") - - local data = {} - data.customarg = false - data.custom = "" - data.legacy = false - data.backwards = false - data.binary = false - data.profid = ID ("dx.profile."..dxprofile) - data.domains = { - [ID "dx.compile.vertex"] = 1, - [ID "dx.compile.fragment"] = 2, - [ID "dx.compile.geometry"] = 3, - [ID "dx.compile.domain"] = 4, - [ID "dx.compile.hull"] = 5, - [ID "dx.compile.compute"] = 6, - [ID "dx.compile.effects"] = 7, - } - data.profiles = { - [ID "dx.profile.dx_2x"] = {"vs_2_0","ps_2_x",false,false,false,false,"fx_2_x",ext=".fxc."}, - [ID "dx.profile.dx_3"] = {"vs_3_0","ps_3_0",false,false,false,false,"fx_3_0",ext=".fxc."}, - [ID "dx.profile.dx_4"] = {"vs_4_0","ps_4_0","gs_4_0",false,false,false,"fx_4_0",ext=".fxc."}, - [ID "dx.profile.dx_5"] = {"vs_5_0","ps_5_0","gs_5_0","ds_5_0","hs_5_0","cs_5_0","fx_5_0",ext=".fxc."}, - } - data.domaindefs = { - " /D _VERTEX_=1 /D _DX_=1 ", - " /D _FRAGMENT_=1 /D _DX_=1 ", - " /D _GEOMETRY_=1 /D _DX_=1 ", - " /D _TESS_CONTROL_=1 /D _DX_=1 ", - " /D _TESS_EVAL_=1 /D _DX_=1 ", - " /D _COMPUTE_=1 /D _DX_=1 ", - " /D _EFFECTS_=1 /D _DX_=1 ", - } - -- Profile related - menuBar:Check(data.profid, true) - - local function selectProfile (id) - for id,profile in pairs(data.profiles) do - menuBar:Check(id, false) - end - menuBar:Check(id, true) - data.profid = id - end - - local function evSelectProfile (event) - local chose = event:GetId() - selectProfile(chose) - end - - for id,profile in pairs(data.profiles) do - frame:Connect(id,wx.wxEVT_COMMAND_MENU_SELECTED,evSelectProfile) - end - - -- Compile Arg - frame:Connect(ID "dx.compile.input",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.customarg = event:IsChecked() - end) - frame:Connect(ID "dx.compile.legacy",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.legacy = event:IsChecked() - end) - frame:Connect(ID "dx.compile.backwards",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.backwards = event:IsChecked() - end) - frame:Connect(ID "dx.compile.binary",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.binary = event:IsChecked() - end) - -- Compile - local function evCompile(event) - local filename,info = GetEditorFileAndCurInfo() - local editor = GetEditor() - local domain = data.domains[event:GetId()] - - if (not (filename and binpath) or not (domain == 7 or info.selword )) then - DisplayOutput("Error: Dx Compile: Insufficient parameters (nofile / no selected entry function!\n") - return - end - - - local profile = data.profiles[data.profid] - if (not profile[domain]) then return end - - -- popup for custom input - data.custom = data.customarg and wx.wxGetTextFromUser("Compiler Args","Dx",data.custom) or data.custom - local args = data.custom:len() > 0 and data.custom or nil - - local fullname = filename:GetFullPath() - - local outname = fullname.."."..(info.selword or "").."^" - outname = args and outname..args:gsub("%s*[%-%/]",";-")..";^" or outname - outname = outname..profile[domain]..profile.ext..(data.binary and "fxo" or "txt") - outname = '"'..outname..'"' - - local cmdline = " /T "..profile[domain].." " - cmdline = cmdline..(args and args.." " or "") - cmdline = cmdline..(data.legacy and "/LD " or "") - cmdline = cmdline..(data.backwards and "/Gec " or "") - cmdline = cmdline..(data.domaindefs[domain]) - cmdline = cmdline..(data.binary and "/Fo " or "/Fc ")..outname.." " - if (info.selword) then - cmdline = cmdline.."/E "..info.selword.." " - end - cmdline = cmdline.."/nologo " - cmdline = cmdline..' "'..fullname..'"' - - cmdline = binpath.."/fxc.exe"..cmdline - - -- run compiler process - CommandLineRun(cmdline,nil,true,nil,nil) - end - - frame:Connect(ID "dx.compile.vertex",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.fragment",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.geometry",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.domain",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.hull",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.compute",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "dx.compile.effects",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - end, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/ffitoapi.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/ffitoapi.lua deleted file mode 100644 index 326a7d9..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/ffitoapi.lua +++ /dev/null @@ -1,313 +0,0 @@ --- author: Christoph Kubisch ---------------------------------------------------------- -local StripCommentsC = StripCommentsC -if not StripCommentsC then - StripCommentsC = function(tx) - local out = "" - local lastc = "" - local skip - local skipline - local skipmulti - local tx = string.gsub(tx, "\r\n", "\n") - for c in tx:gmatch(".") do - local oc = c - local tu = lastc..c - skip = c == '/' - - if ( not (skipmulti or skipline)) then - if (tu == "//") then - skipline = true - elseif (tu == "/*") then - skipmulti = true - c = "" - elseif (lastc == '/') then - oc = tu - end - elseif (skipmulti and tu == "*/") then - skipmulti = false - c = "" - elseif (skipline and lastc == "\n") then - out = out.."\n" - skipline = false - end - - lastc = c - if (not (skip or skipline or skipmulti)) then - out = out..oc - end - end - - return out..lastc - end - -end - -local function ffiToApi(ffidef) - local str = ffidef - str = ffidef:match("(%-%-%[%[.+%]%])") - local header = ffidef:match("[^\r\n]+") - ffidef = StripCommentsC(ffidef) - - local description = header:match("|%s*(.*)") - local descrprefixes = header:match("(.-)%s*|") - if not descrprefixes then return end - - local prefixes = {} - for prefix in descrprefixes:gmatch("([_%w]+)") do - table.insert(prefixes,prefix) - end - local ns = prefixes[1] - if not ns then return end - - local lktypes = { - ["string"] = "string", - } - - local function gencontent(tx) - local enums = {} - local funcs = {} - local values = {} - local classes = {} - - -- extract function names - local curfunc - local function registerfunc() - local fn = curfunc - -- parse args - local args = fn.ARGS:match("%(%s*(.-)%s*%)%s*;") or "" - fn.ARGS = "("..args..")" - - -- skip return void types - local what = fn.RET == "void" and "" or fn.RET - what = what:match("%s*(.-)%s*$") - fn.RET = "("..what..")" - fn.DESCR = "" - if (what ~= "") then - fn.TYPE = what - end - - table.insert(funcs,curfunc) - curfunc = nil - end - - local outer = tx:gsub("(%b{})","{}") - - -- FIXME pattern doesnt recognize multiline defs - for l in outer:gmatch("[^\r\n]+") do - -- extern void func(blubb); - -- extern void ( * func )(blubb); - -- void func(blubb); - -- void ( * func )(blubb); - -- void * ( * func )(blubb); - local typedef = l:match("typedef") - local ret,name,args = string.match(typedef and "" or l, - "%s*([_%w%*%s]+)%s+%(?[%s%*]*([_%w]+)%s*%)?%s*(%([^%(]*;)") - - if (not (curfunc or typedef) and (ret and name and args)) then - ret = ret:gsub("^%s*extern%s*","") - curfunc = {RET=ret,NAME=name,ARGS=args} - registerfunc() - elseif (not typedef) then - local typ,names,val = l:match("%s*([_%w%s%*]+)%s+([_%w%[%]]+)[\r\n%s]*=[\r\n%s]*([_%w]+)[\r\n%s]*;") - if (not (typ and names and val)) then - typ,names = l:match("%s*([_%w%s%*]+)%s+([_%w%[%]%:%s,]+)[\r\n%s]*;") - end - if (typ and names) then - for name,rest in names:gmatch("([_%w]+)([^,]*)") do - rest = rest and rest:gsub("%s","") or "" - local what = typ..(rest:gsub("%b[]","*")) - table.insert(values,{NAME=name, DESCR=(typ..rest..(val and (" = "..val) or "")), TYPE = what,}) - end - end - elseif(typedef) then - -- typedef struct lxgTextureUpdate_s * lxgTextureUpdatePTR; - -- typedef float lxVector2[2]; - local what,name = l:match("typedef%s+([_%w%s%*]-)%s+([_%w%[%]]+)%s*;") - if (what and name) then - what = what:gsub("const%s","") - what = what:gsub("static%s","") - what = what:gsub("%s+"," ") - what = what:gsub("%s+%*","*") - local name,rest = name:match("([_%w]+)(.*)") - rest = rest and rest:gsub("%s","") or "" - if (what and name) then - lktypes[name] = what..(rest:gsub("%b[]","*")) - end - end - end - end - - -- search for enums - for def in tx:gmatch("enum[_%w%s\r\n]*(%b{})[_%w%s\r\n]*;") do - for enum in def:gmatch("([_%w]+).-[,}]") do - table.insert(enums,{NAME=enum}) - end - end - - -- search for classes - for class,def,final in tx:gmatch("struct%s+([_%w]*)[%s\r\n]*(%b{})([_%w%s\r\n]*);") do - final = final:match("[_%w]+") - if (final) then - lktypes["struct "..class] = ns.."."..final - lktypes[final] = ns.."."..final - lktypes[ns.."."..final] = ns.."."..final - else - lktypes["struct "..class] = ns.."."..class - lktypes[ns.."."..class] = ns.."."..class - end - table.insert(classes,{NAME= final or class,DESCR = "",content = gencontent(def:sub(2,-2))}) - end - - return (#classes > 0 or #funcs > 0 or #enums > 0 or #values > 0) and - {classes=classes,funcs=funcs, enums=enums, values=values} - end - - local content = gencontent(ffidef) - local function fixtypes(tab) - for i,v in ipairs(tab) do - local vt = v.TYPE - if (vt) then - local nt = vt - - repeat - nt = nt:match("%s*(.-)%s*$") - nt = nt:gsub("%s+"," ") - nt = nt:gsub("%s%*","*") - nt = nt == "const char*" and "string" or nt - nt = nt:gsub("%*","") - nt = nt:gsub("const%s","") - nt = nt:gsub("static%s","") - vt = nt - local typ,qual = nt:match("([_%w%.%s]+)(%**)") - nt = (lktypes[typ] or "")..(qual or "") - until nt==vt - v.TYPE = nt ~= "" and '"'..nt..'"' or "nil" - else - v.TYPE = "nil" - end - end - end - local function fixcontent(tab) - fixtypes(tab.values) - fixtypes(tab.funcs) - for i,v in ipairs(tab.classes) do - fixcontent(v.content) - end - end - fixcontent(content) - - str = str..[[ - - --auto-generated api from ffi headers - local api = - ]] - - -- serialize api string - local function serialize(str,id,tab,lvl) - lvl = string.rep(" ",lvl or 1) - for i,k in ipairs(tab) do - str = str..string.gsub(id,"%$([%w]+)%$",k):gsub("##",lvl) - end - return str - end - - local function genapi(str,content,lvl) - lvl = lvl or 1 - str = str..string.gsub([[ - ##{ - ]],"##",string.rep(" ",lvl)) - - local value = - [[##["$NAME$"] = { type ='value', description = "$DESCR$", valuetype = $TYPE$, }, - ]] - local enum = - [[##["$NAME$"] = { type ='value', }, - ]] - local funcdef = - [[##["$NAME$"] = { type ='function', - ## description = "$DESCR$", - ## returns = "$RET$", - ## valuetype = $TYPE$, - ## args = "$ARGS$", }, - ]] - str = serialize(str,value,content.values or {},lvl) - str = serialize(str,enum,content.enums or {},lvl) - str = serialize(str,funcdef,content.funcs or {},lvl) - - local classdef = - [[##["$NAME$"] = { type ='class', - ## description = "$DESCR$", - ## $CHILDS$ - ##}, - ]] - for i,v in pairs(content.classes or {}) do - v.CHILDS = v.content and genapi("childs = ",v.content,lvl+1) or "" - end - - str = serialize(str,classdef,content.classes or {},lvl) - - str = str..string.gsub([[ - ##}]],"##",string.rep(" ",lvl)) - - return str - end - - str = genapi(str,content) - - str = str..[[ - - return { - ]] - - local lib = - [[ - $NAME$ = { - type = 'lib', - description = "$DESCR$", - childs = $API$, - }, - ]] - - local libs = {} - for i,prefix in ipairs(prefixes) do - local p = {NAME=prefix, DESCR = description, API="api"} - table.insert(libs,p) - end - - str = serialize(str,lib,libs) - str = str..[[ - } - ]] - - return str -end - -local function exec(wxfname,projectdir) - -- get cur editor text - local editor = GetEditor() - if (not editor) then return end - local tx = editor:GetText() - tx = ffiToApi(tx) - -- replace text - if tx then editor:SetText(tx) end -end - -if (not ide) then - ffitoapi = function(fname) - local f = io.open(fname,"rb") - local tx = f:read("*a") - f:close() - tx = ffiToApi(tx) - local f = io.open(fname,"wb") - f:write(tx) - f:close() - end -end - -return { - exec = { - name = "luajit ffi string to editor api", - description = "converts current file to api, for autocompletion inside this editor", - fn = exec, - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/glslc.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/glslc.lua deleted file mode 100644 index 45ae1ad..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/glslc.lua +++ /dev/null @@ -1,470 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -local binpath = ide.config.path.glslcbin or os.getenv("GLSLC_BIN_PATH") - -return binpath and { - fninit = function(frame,menuBar) - - if (wx.wxFileName(binpath):IsRelative()) then - local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/") - binpath = editorDir..binpath - end - - local myMenu = wx.wxMenu{ - { ID "glslc.compile.input", "&Custom Args", "when set a popup for custom compiler args will be envoked", wx.wxITEM_CHECK }, - { ID "glslc.compile.separable", "Separable", "when set separable programs are used", wx.wxITEM_CHECK }, - { ID "glslc.compile.preproc", "Preprocess File", "Pre-process the files only, resolving #inlcudes", wx.wxITEM_CHECK }, - { }, - { ID "glslc.compile.ext", "Compile from .ext\tCtrl-1", "Compile based on file extension" }, - { ID "glslc.compile.all", "Link multiple .ext\tCtrl-2", "Tries to link multiple shaders based on filename" }, - { ID "glslc.compile.vertex", "Compile &Vertex", "Compile Vertex program" }, - { ID "glslc.compile.fragment", "Compile &Fragment", "Compile Fragment program" }, - { ID "glslc.compile.geometry", "Compile &Geometry", "Compile Geometry program" }, - { ID "glslc.compile.tessctrl", "Compile T.Ctrl", "Compile T.Ctrl program" }, - { ID "glslc.compile.tesseval", "Compile T.Eval", "Compile T.Eval program" }, - { ID "glslc.compile.compute", "Compile Compute", "Compile Compute program" }, - { }, - { ID "glslc.format.asm", "Annotate ASM", "indent and add comments to ASM output" }, - } - menuBar:Append(myMenu, "&GLSL") - - local data = {} - data.customarg = false - data.separable = false - data.preproc = false - data.custom = "" - data.domains = { - [ID "glslc.compile.vertex"] = 1, - [ID "glslc.compile.fragment"] = 2, - [ID "glslc.compile.geometry"] = 3, - [ID "glslc.compile.tessctrl"] = 4, - [ID "glslc.compile.tesseval"] = 5, - [ID "glslc.compile.compute"] = 6, - } - data.domainprofiles = { - "vertex", - "fragment", - "geometry", - "tesscontrol", - "tessevaluation", - "compute", - } - data.domaindefs = { - " -D_VERTEX_ ", - " -D_FRAGMENT_ ", - " -D_GEOMETRY_ ", - " -D_TESS_CONTROL_ ", - " -D_TESS_EVAL_ ", - " -D_COMPUTE_ ", - } - - local function beautifyAsmEach(tx) - local newtx = "" - local indent = 0 - local maxindent = 0 - local isbranch = { - ["IF"]=true,["REP"]=true,["ELSE"]=true,["LOOP"]=true, - } - local startindent = { - ["IF"]=true,["REP"]=true,["ELSE"]=true,["LOOP"]=true,["BB"]=true, - } - local endindent = { - ["ENDIF"]=true,["ENDREP"]=true,["ELSE"]=true,["ENDLOOP"]=true,["END"]=true,["RET"]=true, - } - - local function check(str,tab) - local res - local chk = str:match("%s*(BB)%d+.*:") - chk = chk or str:match("%s*(%w+)") - res = chk and tab[chk] and chk - - return res - end - - local argregistry = {} - local argbuffersfixed = false - - local registercc = 0 - local registermem = 0 - local registers = 0 - local instructions = 0 - local branches = 0 - - local function fixargbuffers() - if (argbuffersfixed) then return end - - local argnew = {} - for i,v in pairs(argregistry) do - local buf,bufstart = string.match(i,"buf(%d+)%[(%d+)%]") - if (buf and bufstart) then - bufstart = tonumber(bufstart)/16 - argnew["buf"..buf.."["..tostring(bufstart).."]"] = v - else - argnew[i] = v - end - end - argregistry = argnew - argbuffersfixed = true - end - - local function checkregistry(w) - local regsuccess = true - - local vtype,vname,sem,resource,pnum,pref = string.match(w,"#var ([_%w]+) ([%[%]%._%w]+) : ([^%:]*) : ([^%:]*) : ([^%:]*) : (%d*)") - local funcname,subroutine = string.match(w,"#function %d+ ([_%w]+)%((%d+)%)") - if (pref == "1") then - local descriptor = vtype.." "..vname - - -- check if resource is array - local resstart,rescnt = string.match(resource,"c%[(%d+)%], (%d+)") - resstart = tonumber(resstart) - rescnt = tonumber(rescnt) - - -- check if resource is buffer/buffer array - local buf,bufstart,bufcnt = string.match(resource,"buffer%[(%d+)%]%[(%d+)%],? ?(%d*)") - buf = tonumber(buf) - bufstart = tonumber(bufstart) - bufcnt = tonumber(bufcnt) - - -- check if texture - local texnum = string.match(resource,"texunit (%d+)") - - local argnames = {} - if (rescnt) then - for i=0,(rescnt-1) do - table.insert(argnames,"c["..tostring(resstart + i).."]") - end - elseif (texnum) then - table.insert(argnames,"texture["..tostring(texnum).."]") - table.insert(argnames,"texture"..tostring(texnum)) - elseif (buf) then - table.insert(argnames,"buf"..tostring(buf).."["..tostring(bufstart).."]") - else - table.insert(argnames,resource) - end - - for i,v in ipairs(argnames) do - argregistry[v] = descriptor - end - elseif (funcname and subroutine) then - argregistry["SUBROUTINENUM("..subroutine..")"] = "function "..funcname - elseif string.find(w,"BUFFER4 ") then - fixargbuffers() - elseif string.find(w,"TEMP ") then - --TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; - --TEMP RC, HC; - --TEMP lmem[9]; - for i in string.gmatch(w,"C") do - registercc = registercc + 1 - end - for i in string.gmatch(w,"R%d+") do - registers = registers + 1 - end - registermem = tonumber(string.match(w,"lmem%[(%d+)%]")) - elseif (string.find(w,"CBUFFER ") or string.find(w,"ATTRIB ") or string.find(w,"OPTION ") or - string.find(w,"OUTPUT ") or string.find(w,"PARAM ") or string.find(w,"!!NV") or - string.find(w,"STORAGE ")) then - - else - regsuccess = false - end - - return regsuccess - end - - local function checkargs(str) - local comment = "#" - local declared = {} - for i in string.gmatch(str,"([%[%]%(%)%w]+)") do - local descr = argregistry[i] - if (descr and not declared[i]) then - comment = comment.." "..i.." = "..descr - declared[i] = true - end - end - - return comment ~= "#" and comment - end - - local registerlevels = {{}} - local function checkregisters(str,indent) - if (indent < 0) then return end - local cur = registerlevels[indent+1] - for i in string.gmatch(str,"R(%d+)") do - cur[i] = true - end - end - - local function clearregisters(indent) - registerlevels[math.max(0,indent)+1] = {} - end - - local function outputregisters(indent) - if (indent < 0) then return "" end - local tab = registerlevels[indent+1] - local out = {} - for i,v in pairs(tab) do - table.insert(out,i) - end - table.sort(out) - local cnt = #out - if (cnt < 1) then return "" end - - local str = string.rep(" ",indent).."# "..tostring(cnt).." R used: " - for i,v in ipairs(out) do - str = str..tostring(v)..((i==cnt) and "" or ", ") - end - return str.."\n" - end - - -- check declarations - local lastline = "" - local addinstr = false - for w in string.gmatch(tx, "[^\n]*\n") do - if (not checkregistry(w)) then - - if (not w:match("%s*#")) then - instructions = instructions + 1 - end - - if (check(w,isbranch)) then - branches = branches + 1 - end - - if (check(w,endindent)) then - newtx = newtx..outputregisters(indent) - if (indent == 0) then clearregisters(indent) end - indent = math.max(0,indent - 1) - end - - local firstchar = string.sub(w,1,1) - local indentstr = (firstchar ~= " " and firstchar ~= "\t" and string.rep(" ",indent) or "") - local linestr = indentstr..w - local argcomment = (firstchar ~= "#") and checkargs(w) - - checkregisters(w,indent) - - newtx = newtx..(argcomment and (indentstr..argcomment.."\n") or "") - newtx = newtx..linestr - - if (check(w,startindent)) then - indent = indent + 1 - maxindent = math.max(maxindent,indent) - clearregisters(indent) - end - else - newtx = newtx..w - end - lastline = w - end - - local registers = tonumber(string.match(lastline, "(%d+) R%-regs")) or registers - registermem = registermem or 0 - registercc = registercc or 0 - local stats = "# "..instructions.." ~ instructions\n" - stats = stats.."# "..branches.." ~ branches\n" - stats = stats.."# "..registers.." R-regs\n" - stats = stats.."# "..tostring(registercc).." C-regs, "..tostring(registermem).." L-regs\n" - stats = stats.."# "..tostring(registercc + registermem + registers).." maximum registers\n" - stats = stats.."# "..maxindent.." maximum nesting level\n" - newtx = newtx..stats.."\n" - - return newtx,stats - end - local function beautifyAsm(tx) - local newtx = "" - local stats - for t in tx:gmatch("!!.-END[^%w]%s*") do - local nt - nt,stats = beautifyAsmEach(t) - newtx = newtx..nt - end - return newtx,stats - end - - local function beautifyAsmFile(filePath) - local file_text = "" - local statlines = "" - local handle = io.open(filePath, "rb") - if handle then - file_text = handle:read("*a") - file_text,statlines = beautifyAsm(file_text) - handle:close() - end - - if (file_text == "") then return end - - local handle = io.open(filePath, "wb") - if handle then - handle:write(file_text) - handle:close() - end - return statlines - end - - -- Compile Arg - frame:Connect(ID "glslc.compile.input",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.customarg = event:IsChecked() - end) - - frame:Connect(ID "glslc.compile.separable",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.separable = event:IsChecked() - end) - - frame:Connect(ID "glslc.compile.preproc",wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - data.preproc = event:IsChecked() - end) - - -- Compile - local function evCompile(event) - local filename,info = GetEditorFileAndCurInfo() - local editor = GetEditor() - local glsl = true - - if (not (filename and binpath)) then - DisplayOutput("Error: GLSL Compile: Insufficient parameters (nofile)\n") - return - end - - local function getDomain(filename) - local fname = filename:GetFullName() - if (fname:match("%.v")) then - domain = 1 - elseif (fname:match("%.f")) then - domain = 2 - elseif (fname:match("%.ge")) then - domain = 3 - elseif (fname:match("%.t.*c")) then - domain = 4 - elseif (fname:match("%.t.*e")) then - domain = 5 - elseif (fname:match("%.c")) then - domain = 6 - end - if (not domain) then - DisplayOutput("Error: GLSL Compile: could not derive domain\n") - end - return domain - end - - local function getCompileArg(filename,domain) - local str = "" - if (data.preproc) then - str = '-P "'..filename:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR).."_"..filename:GetFullName()..'" ' - end - return str.."-profile "..data.domainprofiles[domain]..' "'..filename:GetFullPath()..'" ' - end - - - local outname - local outsuffix - local compileargs - local getinstructions - - if (event:GetId() == ID "glslc.compile.all") then - -- look for multiple files to link - local basename = filename:GetFullName():match(".-%.") - - outname = filename:GetPathWithSep()..basename - - local cnt,files = wx.wxDir.GetAllFiles(filename:GetPathWithSep(), basename.."*" ) - compileargs = "" - for i,v in ipairs(files) do - local filename = wx.wxFileName(v) - if (filename:GetExt() ~= "glp" and - filename:GetExt() ~= "bak") - then - local domain = getDomain(filename) - if (not domain) then - return - end - compileargs = compileargs..getCompileArg(filename,domain) - end - end - - else - -- compile single file - getinstructions = true - - local domain = data.domains[event:GetId()] - if (not domain) then - domain = getDomain(filename) - end - if (not domain) then - return - end - - local profile = data.domainprofiles[domain] - local fullname = filename:GetFullPath() - - outname = fullname.."." - outsuffix = profile - compileargs = data.domaindefs[domain].." "..getCompileArg(filename,domain) - end - - -- popup for custom input - data.custom = data.customarg and wx.wxGetTextFromUser("Compiler Args","GLSLC",data.custom) or data.custom - local args = data.customarg and data.custom or "" - args = args:len() > 0 and args or nil - - outname = outname..(args and "^"..args:gsub("%s*[%-%/]",";-")..";^" or "") - outname = outname..(outsuffix or "") - outname = outname..((outsuffix or args) and "." or "").."glp" - outname = '"'..outname..'"' - - local cmdline = binpath.."/glslc.exe " - cmdline = cmdline..(args and args.." " or "") - cmdline = cmdline..(data.preproc and "-E " or "") - cmdline = cmdline..(data.separable and "-separable " or "") - cmdline = cmdline.."-o "..outname.." " - cmdline = cmdline..compileargs - - local function compilecallback(str) - local postfunc - -- check for errors, if none, launch nvperf - -- and indentation - if (string.find(str,"successfully linked")) then - postfunc = function() - -- beautify asm - if (true) then - local statlines = beautifyAsmFile(outname:sub(2,-2)) - if (getinstructions) then - DisplayOutput(statlines) - end - end - end - end - - return str,postfunc - end - - local wdir = filename:GetPath(wx.wxPATH_GET_VOLUME) - - -- run compiler process - CommandLineRun(cmdline,wdir,true,nil,compilecallback) - - end - - frame:Connect(ID "glslc.compile.vertex",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.fragment",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.geometry",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.tessctrl",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.tesseval",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.compute",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.ext",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - frame:Connect(ID "glslc.compile.all",wx.wxEVT_COMMAND_MENU_SELECTED,evCompile) - - -- indent asm - frame:Connect(ID "glslc.format.asm", wx.wxEVT_COMMAND_MENU_SELECTED, - function(event) - local curedit = GetEditor() - local newtx = beautifyAsm( curedit:GetText() ) - - curedit:SetText(newtx) - end) - end, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_edit.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_edit.lua deleted file mode 100644 index ab1b6f5..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_edit.lua +++ /dev/null @@ -1,14 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -return { - exec = { - name = "Perforce edit", - description = "does p4 edit", - fn = function(fname,projectdir) - local cmd = 'p4 edit "'..fname..'"' - - CommandLineRun(cmd,nil,true) - end, - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_revert.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_revert.lua deleted file mode 100644 index d1e133a..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/tools/perforce_revert.lua +++ /dev/null @@ -1,14 +0,0 @@ --- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) ---------------------------------------------------------- - -return { - exec = { - name = "Perforce revert", - description = "does p4 revert", - fn = function(fname,projectdir) - local cmd = 'p4 revert "'..fname..'"' - - CommandLineRun(cmd,nil,true) - end, - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/app.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/app.lua deleted file mode 100644 index e597fad..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/app.lua +++ /dev/null @@ -1,53 +0,0 @@ -local skipspecs = { - cg = true, glsl = true, luxres = true, opencl = true, sql = true, - cbase = true, hlsl = true, oglgpuprog = true, ptx = true, text = true, -} -return { - loadfilters = { - tools = function(file) return false end, - specs = function(file) return not skipspecs[file:match('spec[/\\]([^/\\]+)%.lua$') or ''] end, - interpreters = function(file) return not file:find('estrela') end, - }, - - postinit = function () - local ide = ide - local bundle = wx.wxIconBundle() - local files = FileSysGetRecursive(ide:GetAppName().."/res", false, "*.ico") - local icons = 0 - for i,file in ipairs(files) do - icons = icons + 1 - bundle:AddIcon(file, wx.wxBITMAP_TYPE_ICO) - end - if icons > 0 then ide.frame:SetIcons(bundle) end - - local menuBar = ide.frame.menuBar - menuBar:Check(ID_CLEAROUTPUT, true) - - -- load myprograms/welcome.lua if exists and no projectdir - local projectdir = ide.config.path.projectdir - if (not projectdir or string.len(projectdir) == 0 - or not wx.wxFileName(projectdir):DirExists()) then - local home = wx.wxGetHomeDir():gsub("[\\/]$","") - for _,dir in pairs({home, home.."/Desktop", ""}) do - local fn = wx.wxFileName("myprograms/welcome.lua") - -- normalize to absolute path - if fn:Normalize(wx.wxPATH_NORM_ALL, dir) and fn:FileExists() then - LoadFile(fn:GetFullPath(),nil,true) - ProjectUpdateProjectDir(fn:GetPath(wx.wxPATH_GET_VOLUME)) - break - end - end - end - end, - - stringtable = { - editor = "ZeroBrane Studio", - about = "About ZeroBrane Studio", - editormessage = "ZeroBrane Studio Message", - statuswelcome = "Welcome to ZeroBrane Studio", - settingsapp = "ZeroBraneStudio", - settingsvendor = "ZeroBraneLLC", - logo = "res/zerobrane.png", - help = "zerobranestudio", - }, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/config.lua b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/config.lua deleted file mode 100644 index f58b09d..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/config.lua +++ /dev/null @@ -1,38 +0,0 @@ -local G = ... -- this now points to the global environment -local ide, wx = G.ide, G.wx -local mac = ide.osname == 'Macintosh' -local win = ide.osname == "Windows" -if mac then - local defaultsize = 11 - filetree.fontsize = defaultsize - if ide.wxver >= "2.9.5" then - editor.fontsize = defaultsize+1 - outputshell.fontsize = defaultsize - end - - editor.fontname = "Monaco" - outputshell.fontname = editor.fontname -else - local defaultsize = 10 - editor.fontsize = defaultsize+1 - outputshell.fontsize = defaultsize - - local sysid, major, minor = wx.wxGetOsVersion() - editor.fontname = - win and (major == 5 and "Courier New" or "Consolas") or "Monospace" - outputshell.fontname = editor.fontname -end - -hidpi = mac -- support Retina displays by default (OSX) -singleinstance = not mac - -unhidewindow = { -- allow unhiding of GUI windows - -- 1 - show if hidden, 0 - ignore, 2 -- hide if shown - ConsoleWindowClass = 2, - -- ignore the following windows when "showing all" - IME = 0, - wxDisplayHiddenWindow = 0, - ['MSCTFIME UI'] = 0, - -- GLUT/opengl/SDL applications (for example, moai or love2d) - GLUT = 1, FREEGLUT = 1, SDL_app = 1, -} diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/BOOKMARK-TOGGLE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/BOOKMARK-TOGGLE.png deleted file mode 100644 index 6f9860e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/BOOKMARK-TOGGLE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAK.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAK.png deleted file mode 100644 index 53a98d5..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAK.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png deleted file mode 100644 index dca5604..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-CALLSTACK.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-CALLSTACK.png deleted file mode 100644 index 2a063aa..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-CALLSTACK.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-DETACH.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-DETACH.png deleted file mode 100644 index a585b87..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-DETACH.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-RUN-TO.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-RUN-TO.png deleted file mode 100644 index 3aa4244..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-RUN-TO.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-START.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-START.png deleted file mode 100644 index 0da42b6..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-START.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-INTO.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-INTO.png deleted file mode 100644 index 51a0e38..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-INTO.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OUT.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OUT.png deleted file mode 100644 index 88aa038..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OUT.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OVER.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OVER.png deleted file mode 100644 index 91547aa..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OVER.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STOP.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STOP.png deleted file mode 100644 index af5225c..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-STOP.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-WATCH.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-WATCH.png deleted file mode 100644 index f1cfcb4..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DEBUG-WATCH.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP-FILE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP-FILE.png deleted file mode 100644 index 77b8645..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP-FILE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP.png deleted file mode 100644 index ff33594..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/DIR-SETUP.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-KNOWN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-KNOWN.png deleted file mode 100644 index 6bcaf21..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-KNOWN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NEW.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NEW.png deleted file mode 100644 index 256cdaa..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NEW.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL-START.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL-START.png deleted file mode 100644 index 16d65bf..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL-START.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL.png deleted file mode 100644 index c7c4d19..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-OPEN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-OPEN.png deleted file mode 100644 index 0a487c2..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-OPEN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE-ALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE-ALL.png deleted file mode 100644 index 790474b..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE-ALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE.png deleted file mode 100644 index c0cfaae..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FILE-SAVE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-AND-REPLACE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-AND-REPLACE.png deleted file mode 100644 index 881c274..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-AND-REPLACE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-IN-FILES.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-IN-FILES.png deleted file mode 100644 index fe653f7..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-IN-FILES.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png deleted file mode 100644 index 9db97e7..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CONTEXT.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CONTEXT.png deleted file mode 100644 index addb686..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CONTEXT.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-DOWN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-DOWN.png deleted file mode 100644 index da250b3..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-DOWN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png deleted file mode 100644 index 02a1175..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-REGEX.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-REGEX.png deleted file mode 100644 index 8620d1e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-REGEX.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SELECTION.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SELECTION.png deleted file mode 100644 index 962addb..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SELECTION.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SETDIR.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SETDIR.png deleted file mode 100644 index 69c52ec..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SETDIR.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SUBDIR.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SUBDIR.png deleted file mode 100644 index 382b6e7..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SUBDIR.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WORD.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WORD.png deleted file mode 100644 index 7519021..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WORD.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png deleted file mode 100644 index 04928a2..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-REPLACE-NEXT.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-REPLACE-NEXT.png deleted file mode 100644 index e5feec3..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND-REPLACE-NEXT.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND.png deleted file mode 100644 index f3b1975..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FIND.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER-MAPPED.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER-MAPPED.png deleted file mode 100644 index 3aedaf7..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER-MAPPED.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER.png deleted file mode 100644 index 4f0fa17..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/FOLDER.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/LICENSE b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/LICENSE deleted file mode 100644 index 24e1714..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Icons are based on the icon set used in LuaEdit. Some of the icons -have been modified to avoid using the last line that is not displayed -correctly in wxLua. - -These icons are licenced under MIT license by permission from -Jean-Francois Goulet (granted on 2012/01/02). - -LuaEdit - -Copyright © 2004-2009 Jean-Francois Goulet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN-NOW.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN-NOW.png deleted file mode 100644 index c6483db..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN-NOW.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN.png deleted file mode 100644 index c39ab44..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/RUN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-ACALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-ACALL.png deleted file mode 100644 index 53ed38e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-ACALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-CALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-CALL.png deleted file mode 100644 index 7603329..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-CALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-GCALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-GCALL.png deleted file mode 100644 index 3450300..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-GCALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LCALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LCALL.png deleted file mode 100644 index 3d3c18e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LCALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LOCAL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LOCAL.png deleted file mode 100644 index ff2971d..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-LOCAL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-SCALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-SCALL.png deleted file mode 100644 index 22632b9..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-SCALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-UP.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-UP.png deleted file mode 100644 index 585a8df..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/16/VALUE-UP.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/BOOKMARK-TOGGLE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/BOOKMARK-TOGGLE.png deleted file mode 100644 index 906ac51..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/BOOKMARK-TOGGLE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAK.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAK.png deleted file mode 100644 index 650d1cf..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAK.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png deleted file mode 100644 index 7ec0859..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-CALLSTACK.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-CALLSTACK.png deleted file mode 100644 index 8915230..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-CALLSTACK.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-DETACH.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-DETACH.png deleted file mode 100644 index 7fd947f..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-DETACH.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-RUN-TO.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-RUN-TO.png deleted file mode 100644 index 262ccb4..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-RUN-TO.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-START.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-START.png deleted file mode 100644 index e89596a..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-START.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-INTO.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-INTO.png deleted file mode 100644 index 1dbd011..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-INTO.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OUT.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OUT.png deleted file mode 100644 index 5d17d66..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OUT.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OVER.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OVER.png deleted file mode 100644 index 8f977cd..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OVER.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STOP.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STOP.png deleted file mode 100644 index 7a2565c..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-STOP.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-WATCH.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-WATCH.png deleted file mode 100644 index e3e6cc5..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DEBUG-WATCH.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP-FILE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP-FILE.png deleted file mode 100644 index ebc1231..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP-FILE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP.png deleted file mode 100644 index 8b6a93b..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/DIR-SETUP.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-NEW.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-NEW.png deleted file mode 100644 index c51d592..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-NEW.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-OPEN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-OPEN.png deleted file mode 100644 index a27e760..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-OPEN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE-ALL.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE-ALL.png deleted file mode 100644 index d9a2547..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE-ALL.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE.png deleted file mode 100644 index ca2b9cc..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FILE-SAVE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-AND-REPLACE.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-AND-REPLACE.png deleted file mode 100644 index a4fe02f..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-AND-REPLACE.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-IN-FILES.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-IN-FILES.png deleted file mode 100644 index c04be5e..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND-IN-FILES.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND.png deleted file mode 100644 index d6bc068..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/FIND.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/LICENSE b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/LICENSE deleted file mode 100644 index 12949b4..0000000 --- a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Icons are based on the icon set used in LuaEdit. -These icons have been manually converted and updated for 24 pixels. - -These icons are licenced under MIT license by permission from -Jean-Francois Goulet (granted on 2012/01/02). - -LuaEdit - -Copyright 2004-2009 Jean-Francois Goulet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN-NOW.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN-NOW.png deleted file mode 100644 index eecc3a0..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN-NOW.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN.png deleted file mode 100644 index 5f8571b..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/24/RUN.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/estrela.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/estrela.png deleted file mode 100644 index 6a954c3..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/estrela.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zbstudio.ico b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zbstudio.ico deleted file mode 100644 index 323776d..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zbstudio.ico and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zerobrane.png b/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zerobrane.png deleted file mode 100644 index 2f270fb..0000000 Binary files a/android/tools/zbstudio.app/Contents/ZeroBraneStudio/zbstudio/res/zerobrane.png and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeDirectory b/android/tools/zbstudio.app/Contents/_CodeSignature/CodeDirectory deleted file mode 100644 index da7b9a1..0000000 Binary files a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeDirectory and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeRequirements b/android/tools/zbstudio.app/Contents/_CodeSignature/CodeRequirements deleted file mode 100644 index 3689088..0000000 Binary files a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeRequirements and /dev/null differ diff --git a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeResources b/android/tools/zbstudio.app/Contents/_CodeSignature/CodeResources deleted file mode 100644 index 9ce5f90..0000000 --- a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeResources +++ /dev/null @@ -1,1542 +0,0 @@ - - - - - files - - Resources/zbstudio.icns - - fAq/1dLaG+6WoxigJfJPCAIIAdI= - - - files2 - - Resources/zbstudio.icns - - fAq/1dLaG+6WoxigJfJPCAIIAdI= - - ZeroBraneStudio/CHANGELOG.md - - 389/ac8lnEkcvBZ7SuiBUtRHhW8= - - ZeroBraneStudio/LICENSE - - zXv4hZ4dB4z2XqH+p40slvC+BH8= - - ZeroBraneStudio/README.md - - yjvk2TsqJMvViVBHxw87+lhbdGk= - - ZeroBraneStudio/api/cg/stdlib.lua - - J962ACcBR5TxAH81f4oZ4yJnJKw= - - ZeroBraneStudio/api/glsl/std.lua - - QKUaZs2SaU5VyFg174lWXsJt+KU= - - ZeroBraneStudio/api/lua/anttweakbar.lua - - EQis/QCfmY9C/DIg1tAXRGg+FaA= - - ZeroBraneStudio/api/lua/assimp20.lua - - 9SRQIjoNoTnnS1PbrYZHPVN1WLw= - - ZeroBraneStudio/api/lua/baselib.lua - - USD3nz0Z6JgqIcAPa9cfgwT4Exk= - - ZeroBraneStudio/api/lua/corona.lua - - 7w7/Yke0QgaZFpvQ+bOZipOMRqU= - - ZeroBraneStudio/api/lua/gideros.lua - - t/fvzwQwsa+UMeaelrdUTzBOKnQ= - - ZeroBraneStudio/api/lua/glewgl.lua - - kltmNE25IRQ9dQbf/fcA1Roadxc= - - ZeroBraneStudio/api/lua/glfw.lua - - 2zREP03MS5XfhXrsuCTs/PBdPRs= - - ZeroBraneStudio/api/lua/glfw3.lua - - 7Fc6UjxjxS6oPuTn2zgjLN61EMg= - - ZeroBraneStudio/api/lua/love2d.lua - - kKww40D3TbZi8sl2HScoqLgWeyc= - - ZeroBraneStudio/api/lua/luajit2.lua - - Z3dEwTNzj4GdMZ027CGDA0uzafg= - - ZeroBraneStudio/api/lua/luxiniaapi.lua - - EhZ25nxih+gaVpI1MB9GyevN6Qk= - - ZeroBraneStudio/api/lua/marmalade.lua - - TZ+ezGYzlRn+EjZBkaBubFpyRKk= - - ZeroBraneStudio/api/lua/moai.lua - - ROc7secSPkln9sdFIFvSxfVznSw= - - ZeroBraneStudio/api/lua/wxwidgets.lua - - mAA3wxfh7qsdKkydvX2TVkd5+ZU= - - ZeroBraneStudio/api/opencl/std.lua - - TTuLjL4mtoe3qzaoGv8GbgjuDnA= - - ZeroBraneStudio/bin/clibs/git/core.dylib - - 6IynpMJGolpnMEhK78gtHAlfxVI= - - ZeroBraneStudio/bin/clibs/lfs.dylib - - bCdZHehDBvz2wbXbvdRZiMbmPig= - - ZeroBraneStudio/bin/clibs/mime/core.dylib - - EF+0HLyzDcIy1t3uhTOcWDm2Guo= - - ZeroBraneStudio/bin/clibs/socket/core.dylib - - Q0li1nnqXj8mzclSijvdb5HQd1Y= - - ZeroBraneStudio/bin/clibs52/mime/core.dylib - - 5ovZvrWOSKYjIhDAqWdWxdI8oYM= - - ZeroBraneStudio/bin/clibs52/socket/core.dylib - - 5O+aS3PaVlW+7FpWertbap76eFc= - - ZeroBraneStudio/bin/clibs53/mime/core.dylib - - H5Te7bRXjD89n4PHtEloSbZ1PiI= - - ZeroBraneStudio/bin/clibs53/socket/core.dylib - - d8WwEfrkPxr8WDgLd8TTZYndzm8= - - ZeroBraneStudio/bin/liblua.dylib - - MgN1w1xeH0xlhb93qno1v5LT6bE= - - ZeroBraneStudio/bin/liblua52.dylib - - o8IQkfkfYZq1E5b6QKJEzthp90A= - - ZeroBraneStudio/bin/liblua53.dylib - - p0EC14kISyhWR3BQYCdhnxVds2Q= - - ZeroBraneStudio/bin/libwx.dylib - - a9Yt+by8Av438fSltsTN07shbjo= - - ZeroBraneStudio/bin/lua - - symlink - lua.app/Contents/MacOS/lua - - ZeroBraneStudio/bin/lua.app/Contents/Info.plist - - cb7qrbuIqqmMGTR2j41Q50ZM3bM= - - ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua - - X5eYrnOsXS/PGuXvoT32Al22CHg= - - ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua52 - - W0uRtUUbs2WipyAdO4+zLcZ1Arg= - - ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua53 - - mYtUZyBUjdcI+iqH0KCmnaQmmzM= - - ZeroBraneStudio/bin/lua52 - - symlink - lua.app/Contents/MacOS/lua52 - - ZeroBraneStudio/bin/lua53 - - symlink - lua.app/Contents/MacOS/lua53 - - ZeroBraneStudio/cfg/estrela.lua - - T6flIdJbLv9MZvNTS1iQe8PlzzM= - - ZeroBraneStudio/cfg/i18n/cn.lua - - bfykj/CBQ5u1ij5KzqBd3USGhnQ= - - ZeroBraneStudio/cfg/i18n/de.lua - - jLi/5haaiNa9I95T7UeCMXgFc+4= - - ZeroBraneStudio/cfg/i18n/en.lua - - nI9ljI7bHyBJwaoQpmNYzfgWIoE= - - ZeroBraneStudio/cfg/i18n/eo.lua - - gmfa7Ku5F08fo/mHJ+RGuSqYFFs= - - ZeroBraneStudio/cfg/i18n/es.lua - - o+r1P4PMQutUygEg32aB4QNo+68= - - ZeroBraneStudio/cfg/i18n/fr.lua - - Lefhtu5jY/4oduyNh47eEpjCe20= - - ZeroBraneStudio/cfg/i18n/it.lua - - /3SMtYtx2krXvayLUnWfUeQqmGc= - - ZeroBraneStudio/cfg/i18n/pt-br.lua - - WWs/Y7bnqAWBVDJX2s7LBMjEL/c= - - ZeroBraneStudio/cfg/i18n/ru.lua - - 1ntkLCK9V2U5jcb9Y/Vineoskkk= - - ZeroBraneStudio/cfg/scheme-picker.lua - - 7i+O64xBUHdFKCoj7VZwsuo65EI= - - ZeroBraneStudio/cfg/tomorrow.lua - - 8cocHOIMywRv0WxfXxuCn7iuoGs= - - ZeroBraneStudio/cfg/user-sample.lua - - XVO+VRGoHQAysEgX9t8hSKPRP+0= - - ZeroBraneStudio/cfg/xcode-keys.lua - - fdDHTWVDsgKNBUxx6/LAEVmKvDw= - - ZeroBraneStudio/interpreters/busted.lua - - QBTQslol4IrOhactovfKK5OYS1M= - - ZeroBraneStudio/interpreters/corona.lua - - +OTIeJSsOUIVbgNTsb6kgz4a304= - - ZeroBraneStudio/interpreters/estrelashell.lua - - FVz1wQoDsCOTbPTap/KWYhVimds= - - ZeroBraneStudio/interpreters/gideros.lua - - 0+Ml0E0P0FyflzTERQep+YhQcEA= - - ZeroBraneStudio/interpreters/gslshell.lua - - X2MwEh+rw0j62a+dZXBOpEnW3aI= - - ZeroBraneStudio/interpreters/lfw.lua - - A6sod9qpJWV/7rTHzZrxzxVdRaM= - - ZeroBraneStudio/interpreters/love2d.lua - - R7tob7JDY4XNeP+ex3lpJAcOvrQ= - - ZeroBraneStudio/interpreters/luabase.lua - - PXQMxVNAMluoxGIewe/mCdW+Ayk= - - ZeroBraneStudio/interpreters/luadeb.lua - - t/G4B4mU7+kXxwvnzzh2vsuYYkA= - - ZeroBraneStudio/interpreters/luadeb52.lua - - WPYAilRzn6jajvOu/wFYPkFFFBM= - - ZeroBraneStudio/interpreters/luadeb53.lua - - q7mW+NctO2qE6FICstoPDABLT/0= - - ZeroBraneStudio/interpreters/luxinia.lua - - Jy3imwWBflzx1jufCEpuVZvRyS4= - - ZeroBraneStudio/interpreters/luxinia2.lua - - SgSNrTi9qW7knCaHSJmkR2m1+7s= - - ZeroBraneStudio/interpreters/marmalade.lua - - oZ8EgluRsBI8EtjbI5XeLaXUTXU= - - ZeroBraneStudio/interpreters/moai.lua - - nBufh9qE284vSG668m3lDGMJq6A= - - ZeroBraneStudio/lualibs/copas/copas.lua - - gJkTh16+rBOqpHde/Jkla+4zusY= - - ZeroBraneStudio/lualibs/coxpcall/coxpcall.lua - - HtlYolIwo55kEMmqksSjUsR1R5Q= - - ZeroBraneStudio/lualibs/dist/config.lua - - tLcopzHT262Sf+0ZuoQikxve7Hk= - - ZeroBraneStudio/lualibs/dist/constraints.lua - - 2eyeiAIgds8Etl3Fslbm6Jtnh1I= - - ZeroBraneStudio/lualibs/dist/depends.lua - - WRLQiXC46uXzlDzMvEtHVZoch6s= - - ZeroBraneStudio/lualibs/dist/git.lua - - VH+kxcruZQTB3sfPkRZWaV0tXc8= - - ZeroBraneStudio/lualibs/dist/init.lua - - M2HLa3OXwqMllndC4f4fGspzWvY= - - ZeroBraneStudio/lualibs/dist/logger.lua - - J71bk8Kxxf2OU3PC3BIUSaKoQd8= - - ZeroBraneStudio/lualibs/dist/manifest.lua - - RYE1YltrQUW5mo4CJA7beHYwXsU= - - ZeroBraneStudio/lualibs/dist/package.lua - - QKQPdbB9zhVh1JG36J8QFQrm3Q4= - - ZeroBraneStudio/lualibs/dist/sys.lua - - SDeJsF3TXd8V8M+hZ1QA9DOB6eg= - - ZeroBraneStudio/lualibs/dist/utils.lua - - dpRuszYnj986IFH9J0ZnnN+AbDM= - - ZeroBraneStudio/lualibs/git.lua - - zUizWJdu8wTbOYx3UBmZ1fqS/1U= - - ZeroBraneStudio/lualibs/git/objects.lua - - WLop1CKm0v5sW44BbjSoTdf3NH0= - - ZeroBraneStudio/lualibs/git/pack.lua - - lzcHA9gisnXUbMXMcWBunoOrAvs= - - ZeroBraneStudio/lualibs/git/protocol.lua - - 854R0Fnn5iDBM1+2TQejZvrvcVU= - - ZeroBraneStudio/lualibs/git/repo.lua - - e2U3L8u15ruCGUfuZox4X/35fTo= - - ZeroBraneStudio/lualibs/git/util.lua - - BM8HoonJbPrSpjs0neFCLSUHLtE= - - ZeroBraneStudio/lualibs/ltn12.lua - - k9ieVja7Rgl1dn044pm1IEJ3rmc= - - ZeroBraneStudio/lualibs/lua_lexer_loose.lua - - 3UMmzBCBXloGFLkH7XK3ZarnUes= - - ZeroBraneStudio/lualibs/lua_parser_loose.lua - - pMgCb8Fb213W/x5lUzPfQ9wcsxo= - - ZeroBraneStudio/lualibs/luadist.lua - - LcGCC9/PgCXO6EOYK+HDkk8TPyI= - - ZeroBraneStudio/lualibs/luainspect/ast.lua - - 3l+Ul3Ntf59cVG9dXsqmanbSbCs= - - ZeroBraneStudio/lualibs/luainspect/compat_env.lua - - 93Q7gSx/tOsg2uVm0+fHQcrO/mI= - - ZeroBraneStudio/lualibs/luainspect/dump.lua - - qiC72/oREZU3eztyJi8Tcr2GWMA= - - ZeroBraneStudio/lualibs/luainspect/globals.lua - - 5VrLL22JFcHoZhIJwtHk4yoOr/0= - - ZeroBraneStudio/lualibs/luainspect/init.lua - - N0l0YVdRosNiRKmOopWL4aVcXT8= - - ZeroBraneStudio/lualibs/luainspect/signatures.lua - - v7m38oKEZ6h6vkOjaDnQ1blBgI4= - - ZeroBraneStudio/lualibs/luainspect/typecheck.lua - - 5rH8puYxEHtLRdY4BuvKpUxKCic= - - ZeroBraneStudio/lualibs/luainspect/types.lua - - pRxmMjTgOdfi162XVpa9yhkgusg= - - ZeroBraneStudio/lualibs/metalua/compiler.lua - - 84aQ9hZ091gZHlLiksoJoLSzDs8= - - ZeroBraneStudio/lualibs/metalua/compiler/parser.lua - - IBuHvzrzeliEC9G7TNaaYQg8b04= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/generator.lua - - LY06SV4Hv3FS3vBL6Yjet0UqN7Q= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/annot/grammar.lua - - zc7R4BlYAcfCxiXAhkE9eaFhGqc= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/common.lua - - jUlHJm8ajT4+iNz93PqgQv3eWsQ= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/expr.lua - - X/77oveQ7adAmwrn7s4ubbdX3+Y= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/ext.lua - - x2zqKFbz6Arm5tqRJBcRPM2ZqBc= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/lexer.lua - - 81vdinXhOVvpmnendB/osTqP9XA= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/meta.lua - - dr5VcoMj3+WkZK3m36bOAv+0wyQ= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/misc.lua - - +p5BL4auL9FGapiS/1g8MM0l7Ss= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/stat.lua - - MM6KrXqj9JKMd7NME7G1Z9Y9BXk= - - ZeroBraneStudio/lualibs/metalua/compiler/parser/table.lua - - 8UzMCFuTrrMQlTwmE2KKljBMwos= - - ZeroBraneStudio/lualibs/metalua/grammar/generator.lua - - SEfCQ3zL0yzDzwScxfj/FWa2qnU= - - ZeroBraneStudio/lualibs/metalua/grammar/lexer.lua - - CpuNqRAXjs+IP43GgeRY6h6F4Ak= - - ZeroBraneStudio/lualibs/metalua/pprint.lua - - kezhVwWvUcvM1qNx4RcbvPI21XQ= - - ZeroBraneStudio/lualibs/mime.lua - - ep+xHpGUYH+brpjvrEUUIQo/ZZM= - - ZeroBraneStudio/lualibs/mobdebug/mobdebug.lua - - QVjHtlN7Q70OfzkNdI0BgcAZd40= - - ZeroBraneStudio/lualibs/sha2.lua - - QDONZZu+ccwZyllvec9rz51S98Q= - - ZeroBraneStudio/lualibs/socket.lua - - 7XJ9QSAGq4TKEMeJx2Ii7arVJNI= - - ZeroBraneStudio/lualibs/socket/ftp.lua - - k+9XDA4PIxkJOBOw4qCL1weoWCI= - - ZeroBraneStudio/lualibs/socket/headers.lua - - d8O1DLWnMDJpIOU5uF7/gkozzBo= - - ZeroBraneStudio/lualibs/socket/http.lua - - H59/BAfHvhhD0GdtPmkbYpk+t1w= - - ZeroBraneStudio/lualibs/socket/smtp.lua - - C/pq2pOvXatvrnH5QehuaotPKBQ= - - ZeroBraneStudio/lualibs/socket/tp.lua - - KHL2qIDHNrmUUYUvjkRijfT7Gp4= - - ZeroBraneStudio/lualibs/socket/url.lua - - uPzby7+veErL/deI37bImA38GTw= - - ZeroBraneStudio/lualibs/ssl.lua - - r9CtwibIU9fHTt4Cvo2besBKJpM= - - ZeroBraneStudio/lualibs/ssl/https.lua - - FteKuUcEg69n0rv5bmuvLlRGxm8= - - ZeroBraneStudio/lualibs/testwell.lua - - 1iAlxgw0aHnb/R3kcUtpoHvyy5A= - - ZeroBraneStudio/myprograms/LOVE-samples/demo.lua - - dzcocWxkyqorj2uhVfionUcSFPM= - - ZeroBraneStudio/myprograms/LOVE-samples/hello/main.lua - - LZdALQ7ewBKP2m1ZOdqkgJLae0E= - - ZeroBraneStudio/myprograms/LOVE-samples/shooter/main.lua - - bsZpT4ghUVKr2/ApKsH9Bfz0ekE= - - ZeroBraneStudio/myprograms/LOVE-samples/trajectory/conf.lua - - w8WLtdO4Qf98BCXjc119FJGQppw= - - ZeroBraneStudio/myprograms/LOVE-samples/trajectory/main.lua - - Xi9HnSyrfeb/rAuUyUTq2oBVyLg= - - ZeroBraneStudio/myprograms/README.md - - WSqUMzU6Q3dgl97yOkmVPGylCxA= - - ZeroBraneStudio/myprograms/corona-samples/demo.lua - - fTWujdNhK9e0tpimOL6yYBVlqHE= - - ZeroBraneStudio/myprograms/corona-samples/live-coding-simple/main.lua - - R+BUUb5nn5+qm30v31OnsFuvD4M= - - ZeroBraneStudio/myprograms/gideros-samples/demo.lua - - ZbyHBo0zXcPlnpb0AVkHVtlRT9w= - - ZeroBraneStudio/myprograms/gideros-samples/live-coding-simple/live-coding-simple.gproj - - sUlXoGehTZwwubOJ7H0azN4RyK4= - - ZeroBraneStudio/myprograms/gideros-samples/live-coding-simple/main.lua - - FjLBcwqm2GY9HfdNiH+mU4Yk7o8= - - ZeroBraneStudio/myprograms/gideros-samples/live-coding-simple/zbstudio.png - - exaVMV75/Af9k1D3t57ZHVOpiD0= - - ZeroBraneStudio/myprograms/livecoding-samples/demo.lua - - nr7BTf3jTbUoFiFNlKKwlrS7Tdk= - - ZeroBraneStudio/myprograms/livecoding-samples/graph.lua - - 8JlPguoDcgXYOjT6iJGCHpMw3M4= - - ZeroBraneStudio/myprograms/livecoding-samples/simple.lua - - /Xkh6EzVhPE3kI0qKJOPNHnR9u4= - - ZeroBraneStudio/myprograms/livecoding-samples/trajectory.lua - - 3V79f4G1yVFiOTD8VE81AHU4cE0= - - ZeroBraneStudio/myprograms/livecoding-samples/tree.lua - - WKsjLuJQv6tIIam2E+yiX9l5TyY= - - ZeroBraneStudio/myprograms/livecoding-samples/turtle.lua - - 9D6i7JHM5S14rTJElT7dfSXAM/A= - - ZeroBraneStudio/myprograms/moai-samples/demo.lua - - 0TAimzRv3n3I9VQjsj9WMkB1UjA= - - ZeroBraneStudio/myprograms/moai-samples/live-coding-simple/main.lua - - F4jnHeHIOZT5mGttAzodGszZ5II= - - ZeroBraneStudio/myprograms/moai-samples/live-coding-simple/zbstudio.png - - exaVMV75/Af9k1D3t57ZHVOpiD0= - - ZeroBraneStudio/myprograms/programming-lessons/00-contents.lua - - TGuIVx5nPw+cfBQFlUsekmwM3as= - - ZeroBraneStudio/myprograms/programming-lessons/01-progr-start.lua - - sITSg86UJ16eayG+VPYCrn1/c5c= - - ZeroBraneStudio/myprograms/programming-lessons/02-controls.lua - - m+nsxD9vX3bbTTlVfyBURcsYr6A= - - ZeroBraneStudio/myprograms/programming-lessons/03-helloworld.lua - - TefRmE7/5YljJeZrExcdgZAzyXk= - - ZeroBraneStudio/myprograms/programming-lessons/04-instruct.lua - - NCcwIWAOK7zejqD8CZGS8vbkhr0= - - ZeroBraneStudio/myprograms/programming-lessons/05-explain.lua - - ZZKdYK8EjApH9Ld1CukYsiX7PDI= - - ZeroBraneStudio/myprograms/programming-lessons/06-light-bulb.lua - - lPStn2MnJ64rmhM7zDFRcudqhHY= - - ZeroBraneStudio/myprograms/programming-lessons/07-numbers.lua - - 7Zeh/2hp9cJ67bUK09UY/3AKBAs= - - ZeroBraneStudio/myprograms/programming-lessons/08-order.lua - - 3UsTkpG9yek5bVEZeInv+8zD+YI= - - ZeroBraneStudio/myprograms/programming-lessons/09-grouping.lua - - V1zaKbUyoHaUmDY4rid+Oawj/zk= - - ZeroBraneStudio/myprograms/programming-lessons/10-console.lua - - p3ajBqvLQIbZpQ0LwTApq+xQqAY= - - ZeroBraneStudio/myprograms/programming-lessons/11-strings.lua - - ulaqARPoP1EZBWh7DZsaMB123nI= - - ZeroBraneStudio/myprograms/programming-lessons/12-concat.lua - - SyU/x52JJakTtEllnlJL9fcFFK0= - - ZeroBraneStudio/myprograms/programming-lessons/13-format.lua - - O0Ft4Qt41Dj8cLsv4QjVQhmlVVE= - - ZeroBraneStudio/myprograms/programming-lessons/14-r-numbers.lua - - 46QVwQC24UWnVvh3l1fdYlC98QI= - - ZeroBraneStudio/myprograms/programming-lessons/15-r-strings.lua - - BVdsrfzeSD780Jj2NKzQE2hoBwg= - - ZeroBraneStudio/myprograms/programming-lessons/16-e-numbers.lua - - GZOzL3FWuLlGehXqdQttbrUJ6j8= - - ZeroBraneStudio/myprograms/programming-lessons/17-e-strings.lua - - NmAog3io5bhi3+lLuZtdV2g0gWg= - - ZeroBraneStudio/myprograms/quick-start.lua - - ctl1eSkrMu2Hd72GUnHN/klfAhk= - - ZeroBraneStudio/myprograms/spirograph-samples/astroid.lua - - GvZEJNtogD+NUsmkAR3wPMBC46k= - - ZeroBraneStudio/myprograms/spirograph-samples/bud.lua - - KyVXrYnYAUu9XYvga8mBldeUP7w= - - ZeroBraneStudio/myprograms/spirograph-samples/cardioid.lua - - cQ12KPf7BRkYoA2iaXJwYnvLJi0= - - ZeroBraneStudio/myprograms/spirograph-samples/circles.lua - - M/xq1xSvpmiS75J3hrSG5U/0MWw= - - ZeroBraneStudio/myprograms/spirograph-samples/demo.lua - - KuxY6LivIY8QlU8HrTQCOAdItA0= - - ZeroBraneStudio/myprograms/spirograph-samples/donut.lua - - KZDPgyteZBtFNOHm6X/sWODO8S8= - - ZeroBraneStudio/myprograms/spirograph-samples/double.lua - - yDbBCEcphlQhnOc7LyQ5Vf3ohbE= - - ZeroBraneStudio/myprograms/spirograph-samples/earth.lua - - PJ3oFsSgeybPdO8ig7Xse+H2lko= - - ZeroBraneStudio/myprograms/spirograph-samples/flower.lua - - RtKcj6wwd/YCrz3U1K25JnaHg1c= - - ZeroBraneStudio/myprograms/spirograph-samples/galaxy.lua - - KttoXIrrAVKCQLUCVgBHZ6tGlMo= - - ZeroBraneStudio/myprograms/spirograph-samples/pearls.lua - - 3lii60igdruJDrYkAwSCdouAvV0= - - ZeroBraneStudio/myprograms/spirograph-samples/resolution.lua - - nfVohGdZGR37zdn6SFZzKj4bAwU= - - ZeroBraneStudio/myprograms/spirograph-samples/rose.lua - - ZEdNEbrLC3bnB6Dqexkg6iPS4CQ= - - ZeroBraneStudio/myprograms/spirograph-samples/spiral.lua - - 9+KarcBzgEuiQ7WY+lwJK9lXQAE= - - ZeroBraneStudio/myprograms/spirograph-samples/square.lua - - nH1zP0ZHxrCz2WqQwlP9V3jZgwg= - - ZeroBraneStudio/myprograms/spirograph-samples/star.lua - - mv2FzpVIo+VyrCCEjHpTVFNMIWs= - - ZeroBraneStudio/myprograms/spirograph-samples/sunflower.lua - - 27ffGD5lipgeknIBGOUH70443Zc= - - ZeroBraneStudio/myprograms/spirograph.lua - - YQas1J87eWdxNUlt5LDk4Ov6rqU= - - ZeroBraneStudio/myprograms/testwell.lua - - 1iAlxgw0aHnb/R3kcUtpoHvyy5A= - - ZeroBraneStudio/myprograms/turtle-samples/bounce.lua - - fKHiV7vHsSoYsujEbUm7WSgLBeY= - - ZeroBraneStudio/myprograms/turtle-samples/circle.lua - - QfetbiB/idZjzK4ItukaNLEV/D0= - - ZeroBraneStudio/myprograms/turtle-samples/circles.lua - - /Yu7P5HB3kPRHPO/HVcU3xGmCJM= - - ZeroBraneStudio/myprograms/turtle-samples/demo.lua - - LLT/U9txo3kl7+ZnxbE9G8FtkBU= - - ZeroBraneStudio/myprograms/turtle-samples/filter.lua - - GB74oXUrY7c0yBIfYr5JpMTYFCg= - - ZeroBraneStudio/myprograms/turtle-samples/flower.lua - - p5WyhW54MBc5J3jwStWUxG4YeoM= - - ZeroBraneStudio/myprograms/turtle-samples/fractal-koch.lua - - FTzXgl8f91fhvCaUsCcnW+FzKK0= - - ZeroBraneStudio/myprograms/turtle-samples/linearize.lua - - TRBpIMORH4A0UtRRCFSMPwp9B34= - - ZeroBraneStudio/myprograms/turtle-samples/many-turtles.lua - - Lwblafgj3VWiV3YEGy7r2U9Z/t0= - - ZeroBraneStudio/myprograms/turtle-samples/origin.lua - - HZxBWCIrQRBg/QBVFg12gSNNIWM= - - ZeroBraneStudio/myprograms/turtle-samples/pixels.lua - - b4erZgUKbEtPMBnkz6gIQVMxeGk= - - ZeroBraneStudio/myprograms/turtle-samples/rainbow.lua - - l00zvZgNs3B5S/1ZrYlBfCNq064= - - ZeroBraneStudio/myprograms/turtle-samples/rays.lua - - uTbCmF7GALsN8FV7E+4KuVcw2W8= - - ZeroBraneStudio/myprograms/turtle-samples/shell.lua - - SHVtYv1KUMcDKhGcixjR411Pfdw= - - ZeroBraneStudio/myprograms/turtle-samples/snowflake.lua - - 8rRkujXalu/pFre/91MTXTYr9Cs= - - ZeroBraneStudio/myprograms/turtle-samples/spiral-two.lua - - R3Qg0hOEfIfBap/3rlFeXTNsFZI= - - ZeroBraneStudio/myprograms/turtle-samples/squared-rays.lua - - cIVuznaxIuZvhjUCu09TimxRpgM= - - ZeroBraneStudio/myprograms/turtle-samples/squared-spiral.lua - - e0n2MYzOAevgjthYyuVTaPgqGNs= - - ZeroBraneStudio/myprograms/turtle-samples/star.lua - - NGS+R/puAKEjRaauT+B1flEtRoQ= - - ZeroBraneStudio/myprograms/turtle-samples/text.lua - - 1Ck21UVARXPHyHOfJI9LJ9OOTJA= - - ZeroBraneStudio/myprograms/turtle-samples/tree30.lua - - tKVzmRUEvAM9GxOxE9nVGlBUWsI= - - ZeroBraneStudio/myprograms/turtle-samples/tree45.lua - - R4ch0cN7vBsyo3TRhwPhKcbELyA= - - ZeroBraneStudio/myprograms/turtle-samples/tree60.lua - - oThsMxAzcu1LG3eYQstgpLackJs= - - ZeroBraneStudio/myprograms/turtle-samples/wheel.lua - - zL8Glo2cMI+lZfaDe3zl8PABs70= - - ZeroBraneStudio/myprograms/turtle-samples/zerobrane.png - - vLsBc4ANiG934i9y3ikmRX5QSUM= - - ZeroBraneStudio/myprograms/turtle.lua - - +gJKiGnxzRjaIyV6l9nKFUHLBQw= - - ZeroBraneStudio/myprograms/welcome.lua - - Yf+rnTz7dXgv6mqoMCE09Idqqy4= - - ZeroBraneStudio/myprograms/zerobrane-lessons/00-contents.lua - - uwERucJBR0R25LyrB6Ctvii37Dc= - - ZeroBraneStudio/myprograms/zerobrane-lessons/01-zb-start.lua - - Tlrp5mdB0e1+ZF/RYDkK3RnREoA= - - ZeroBraneStudio/myprograms/zerobrane-lessons/02-controls.lua - - Gs352yR77YN54cDKPAq3/TYfPWc= - - ZeroBraneStudio/myprograms/zerobrane-lessons/03-editor.lua - - IP6bPc5CZXyecsRUwCz7uMlOiU0= - - ZeroBraneStudio/myprograms/zerobrane-lessons/04-save-open.lua - - ZBWXQj33fwZXUQ7gHoHFvK8ADzg= - - ZeroBraneStudio/myprograms/zerobrane-lessons/05-running.lua - - WA2BC5TdHvHREPHpZ+qha0xfPn4= - - ZeroBraneStudio/myprograms/zerobrane-lessons/06-output.lua - - vgY2PCm1gGL7Q6eExxldTltB/qk= - - ZeroBraneStudio/myprograms/zerobrane-lessons/07-project.lua - - /W8eyc/ViGGvS2D5lrOVxbzrkUE= - - ZeroBraneStudio/myprograms/zerobrane-lessons/08-toolbar.lua - - jgOFDGfarOEDCtOMIHsKsKuygBQ= - - ZeroBraneStudio/myprograms/zerobrane-lessons/09-adjustment.lua - - TsDUfrKgDRFIXJ6jpSWlC17BoFM= - - ZeroBraneStudio/myprograms/zerobrane-lessons/10-done.lua - - qnr+nWTNX+V09g4BseG9aS6FBFM= - - ZeroBraneStudio/packages/sample.lua - - s2Yz5oNoaTpQaapACStqlZq+/VM= - - ZeroBraneStudio/spec/cbase.lua - - RmxXrXgbm17Ck8wq+lAgsUUG8FY= - - ZeroBraneStudio/spec/cg.lua - - odxUwy09FpeitWJUKHVZTq1fxCQ= - - ZeroBraneStudio/spec/cpp.lua - - z0U0q5B3ygDoMt57ItF1TTcfV00= - - ZeroBraneStudio/spec/glsl.lua - - apL6W0oPw4sMq0tHaGbaAHnXwv4= - - ZeroBraneStudio/spec/hlsl.lua - - WFfRzplHQy7cZdLf4XltIzq5pnY= - - ZeroBraneStudio/spec/html.lua - - jKUtCG8Arz95+OtDtDxbD3lTMMo= - - ZeroBraneStudio/spec/lua.lua - - 14dff+/5+018NNpli9fFqh/5GLk= - - ZeroBraneStudio/spec/luxres.lua - - cssBcZ3Ss4RwBaUOhGSyIu7YQOA= - - ZeroBraneStudio/spec/oglgpuprog.lua - - EG8jpvqBt476202/xmjy0ZY6pHg= - - ZeroBraneStudio/spec/opencl.lua - - IqYttO346Ib190ekOvx2PnyyRA8= - - ZeroBraneStudio/spec/ptx.lua - - 2157wSd4dKiyF55YqRjJoRwdHc0= - - ZeroBraneStudio/spec/sql.lua - - mD2arMqrg7FpwTes2tv4lH9qJMo= - - ZeroBraneStudio/spec/text.lua - - +UnsgwIuAomlDAaBwcT1KRy4YgA= - - ZeroBraneStudio/src/defs.lua - - X+LYl1jJPgYhc1k2d5DvfABkqD0= - - ZeroBraneStudio/src/editor/autocomplete.lua - - 3m5xPjrH9dOD88L/gNATGM+TNFE= - - ZeroBraneStudio/src/editor/commandbar.lua - - C4mPqIw7ss+/lc05YyoLgMmfl+k= - - ZeroBraneStudio/src/editor/commands.lua - - MlJDKI8uLmtCg/AWmQT/Tbs6LIs= - - ZeroBraneStudio/src/editor/debugger.lua - - 7KdcE2x88swbc/UecvVbOE+ZvWo= - - ZeroBraneStudio/src/editor/editor.lua - - XbVOAY6RqKoZE6evzQoLoQizS0s= - - ZeroBraneStudio/src/editor/filetree.lua - - KwYfenVnaw4At1K2goAsZi/Qh2o= - - ZeroBraneStudio/src/editor/findreplace.lua - - jZnLxM89vGyMNUEvBDPi9fki6Oc= - - ZeroBraneStudio/src/editor/gui.lua - - RlNAaT0lHK1GcvoV4QMRpNQCzVo= - - ZeroBraneStudio/src/editor/ids.lua - - awM2MOZTM+rYjoNU4yK/NE1q9QM= - - ZeroBraneStudio/src/editor/inspect.lua - - Rsj6Xyl+ZUIowERHAgXKb5whQ8c= - - ZeroBraneStudio/src/editor/iofilters.lua - - 7Zog3Ej/TwqyEq2L783Bw8mo9os= - - ZeroBraneStudio/src/editor/keymap.lua - - OrSKyE+SyvLj3zhpieXOFZjF3FQ= - - ZeroBraneStudio/src/editor/markers.lua - - R/06eTrFgaNTAKOzWNuZ+E3pTcU= - - ZeroBraneStudio/src/editor/markup.lua - - DnedSfzplWLAW9dQ7i/js03ZdHA= - - ZeroBraneStudio/src/editor/menu_edit.lua - - oOQ1y7L02wkl68rugYNdi9rnOVc= - - ZeroBraneStudio/src/editor/menu_file.lua - - kicnnHu9YloOChgwTanWAfBWiQA= - - ZeroBraneStudio/src/editor/menu_help.lua - - tK4anRV229I4Kc0H4pzGCpi/4Ss= - - ZeroBraneStudio/src/editor/menu_project.lua - - T87cLn/nl/GaM7v/CUvOUoYC5z4= - - ZeroBraneStudio/src/editor/menu_search.lua - - J1mbS1Gr4yzxBt3UPju1gxly0BU= - - ZeroBraneStudio/src/editor/menu_tools.lua - - y1ApOVv0U2m0PQtfjxAbK/smD1k= - - ZeroBraneStudio/src/editor/menu_view.lua - - jzd/Uk9K6CwSAAAHMXOwgYOx9mM= - - ZeroBraneStudio/src/editor/outline.lua - - KeGYtKAx2yslO/cB2mger3XViJY= - - ZeroBraneStudio/src/editor/output.lua - - xIZtbWZOHFtWIEukL2U5ajo89R8= - - ZeroBraneStudio/src/editor/package.lua - - 1OCHaUqDOfjzniJOIXv61e3svu0= - - ZeroBraneStudio/src/editor/print.lua - - VmFgbsLu+8qSEKFkeH0xHkTk4bI= - - ZeroBraneStudio/src/editor/proto.lua - - 6sJshH8T3Qu1eOmZgbwcj0lSovU= - - ZeroBraneStudio/src/editor/settings.lua - - QoCNzgAgEEcQyoRA9+lyzLDo7K0= - - ZeroBraneStudio/src/editor/shellbox.lua - - F0R/x6kki0GfT2gyhJwr3Uxzrpw= - - ZeroBraneStudio/src/editor/singleinstance.lua - - XTdLbGGHV9LQm9LisJCNBf4a4n8= - - ZeroBraneStudio/src/editor/style.lua - - eeZYJhhQNCND6ekgL4D44Lv5zKA= - - ZeroBraneStudio/src/editor/toolbar.lua - - FRrxsjsziLATO7U8TF6pWDBcbHs= - - ZeroBraneStudio/src/main.lua - - of0LwL6bjSLTpTtlF0KfKlZ3Z14= - - ZeroBraneStudio/src/util.lua - - S9x0ntP7cvbIDApuFraLutJVCtQ= - - ZeroBraneStudio/src/version.lua - - +E1RgLZFWInPi3NPfFyCltcpKyw= - - ZeroBraneStudio/tools/cg.lua - - l1NcM03RQj7UiL3ZNh1v5evalNI= - - ZeroBraneStudio/tools/clcc.lua - - jYJv71i1UGJngE9EPaKO1LTZvls= - - ZeroBraneStudio/tools/cstringify.lua - - VZRV2D3tfJBtoKDJqV/yQcCuSXk= - - ZeroBraneStudio/tools/dx.lua - - Ot3p5JyXlVE70J5USJs9keaWYBU= - - ZeroBraneStudio/tools/ffitoapi.lua - - r0c9oU6M9xXtkne8H2T+3KWhZVw= - - ZeroBraneStudio/tools/glslc.lua - - oI0iw4RD2bUm/8ti8jtWQMMr798= - - ZeroBraneStudio/tools/perforce_edit.lua - - GJmbNNzOHdjFMPP9Qr/GJC3FUOM= - - ZeroBraneStudio/tools/perforce_revert.lua - - MpTBxzYDkiyXOO7Qpbt5RcNJKJM= - - ZeroBraneStudio/zbstudio/app.lua - - Lwv94vu87FZO4mjG9T9R2lw65EU= - - ZeroBraneStudio/zbstudio/config.lua - - FLjGBU0ouiGvZOvKgbAsKqYT2a8= - - ZeroBraneStudio/zbstudio/res/16/BOOKMARK-TOGGLE.png - - wJDUf1saYZSNVTRiHzJofKLGGA8= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAK.png - - M3S/2oFe9s5SriwTLulxdb8l398= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png - - Eer6CED2d8p+cs9bhtc//IADua0= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-CALLSTACK.png - - PPuHwD6zkkWEcDrvEyqnFzCgijI= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-DETACH.png - - 4wxC8wwSG/LwYvWze9zroIxAKNg= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-RUN-TO.png - - yKvReuHJr/ldNMeMZId6ylcI8Ss= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-START.png - - 7MK4J5HTiCjWCharabty4BaUayM= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-INTO.png - - 9yAf6KSCxVC2eO8MxaWKHp4OlFA= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OUT.png - - WGri2xMjYYN3/cfq0CCILeZr3Mc= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-STEP-OVER.png - - UMiKthRsOTii5kXRe0JCGkvRGyg= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-STOP.png - - 4ag269SkNTBPlohvQNO6G4XrYVw= - - ZeroBraneStudio/zbstudio/res/16/DEBUG-WATCH.png - - odKESK6OdL0If12mFuvkzrXYX3w= - - ZeroBraneStudio/zbstudio/res/16/DIR-SETUP-FILE.png - - MLxTWEAMQtw0PO37JRhf5pODF8o= - - ZeroBraneStudio/zbstudio/res/16/DIR-SETUP.png - - AifZCro+306WAWBKy5QrXwQU/bg= - - ZeroBraneStudio/zbstudio/res/16/FILE-KNOWN.png - - GBcdgSLysL/VoRwPEzriePrKg4w= - - ZeroBraneStudio/zbstudio/res/16/FILE-NEW.png - - GnAzCsG0zaNWrVzRZCfM6NPyST0= - - ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL-START.png - - GvKNhRxLyRc7fax7TFOpRU+lNBU= - - ZeroBraneStudio/zbstudio/res/16/FILE-NORMAL.png - - ijVAH4p8zS/wkUWuZiN839ysLOQ= - - ZeroBraneStudio/zbstudio/res/16/FILE-OPEN.png - - P1iUKK5/EkY61GmzaReSp1I3p0c= - - ZeroBraneStudio/zbstudio/res/16/FILE-SAVE-ALL.png - - 4BtiUjh6TQ0m39Qi1T4RD5/WS4I= - - ZeroBraneStudio/zbstudio/res/16/FILE-SAVE.png - - PZoVltbTYZU0YcR2ZCZESUZG1lc= - - ZeroBraneStudio/zbstudio/res/16/FIND-AND-REPLACE.png - - syeCbWFx8mVapUUYkKiHTKHeQmI= - - ZeroBraneStudio/zbstudio/res/16/FIND-IN-FILES.png - - 7oY1cLMWMHNWAEgIpZk+bVsFsZw= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png - - gK65PB4mKaEyT4U1W6FB1j1x5pI= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-CONTEXT.png - - ueLZVvCNl473AJbhntqYj6eaeXg= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-DOWN.png - - 4YMTCzubjmiazYh4HJw7RtItXHQ= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png - - 1uwHhzWf8MEkNeOJnFCsD8wUtXI= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-REGEX.png - - VodLwgVbOkRs9aKoHOpUCDpIof0= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SELECTION.png - - zTqJhvbEhpOdnBC2Dhdr6sTS20Q= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SETDIR.png - - qkP3mWl1sWlATr26Zp3Y3br1J9s= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-SUBDIR.png - - OG4IlzEiXzoQuoea1xNcUJeNsN8= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WORD.png - - 8FvXML5vx1cAsyoR0/uAMLbzxd0= - - ZeroBraneStudio/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png - - ToKjJYbP+qeoaZc2SIhLHhpGeTE= - - ZeroBraneStudio/zbstudio/res/16/FIND-REPLACE-NEXT.png - - YvIkpTVLfjITcCRgBqx5ZhdYtww= - - ZeroBraneStudio/zbstudio/res/16/FIND.png - - Nrps+S9fT3l+jCXD8U467AJ1v7I= - - ZeroBraneStudio/zbstudio/res/16/FOLDER-MAPPED.png - - nO2qVn9bacI9CcfYUg5lpL3stxA= - - ZeroBraneStudio/zbstudio/res/16/FOLDER.png - - +Ripl7Xvjkj/qVdibOMj89OCcb8= - - ZeroBraneStudio/zbstudio/res/16/LICENSE - - zpGIqxAlWZQx5zmC76MIMevNJYE= - - ZeroBraneStudio/zbstudio/res/16/RUN-NOW.png - - HrzyzW9dtWvQYaI2EwO3aIDf2cM= - - ZeroBraneStudio/zbstudio/res/16/RUN.png - - 2Nwm+lfT0aEMwv4MG+0IttM4Bzo= - - ZeroBraneStudio/zbstudio/res/16/VALUE-ACALL.png - - IaM0cUJgWpPSnL7MVw74HFOYzUU= - - ZeroBraneStudio/zbstudio/res/16/VALUE-CALL.png - - TpdzcpYGj/o8/Hdtp7yU9RkR7ys= - - ZeroBraneStudio/zbstudio/res/16/VALUE-GCALL.png - - rfMD2CIQcjW0lopVxV7T+HkIArk= - - ZeroBraneStudio/zbstudio/res/16/VALUE-LCALL.png - - SVemTgn28Ju4dvXH32992yshu+s= - - ZeroBraneStudio/zbstudio/res/16/VALUE-LOCAL.png - - DFfihH1madj3hqB2EXmlYDj5itA= - - ZeroBraneStudio/zbstudio/res/16/VALUE-SCALL.png - - jsFptNPXrII8tJVa2qGLMtppTGw= - - ZeroBraneStudio/zbstudio/res/16/VALUE-UP.png - - GDoZ2Dn51nKwKF1IG71Jd4rDT+U= - - ZeroBraneStudio/zbstudio/res/24/BOOKMARK-TOGGLE.png - - +oR32dnMQyY/tbfckL2DNy5/2to= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAK.png - - 1XqWkidaoIJEux8xl1q7URGCsiA= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png - - k0j6hOieCjhA5ilGZ8FwysFuckk= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-CALLSTACK.png - - AHz1VVOAMqBJ8VBzNn/ar9ZXko0= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-DETACH.png - - DPtJQ5ykWMXhYNWHJfPdoag00hI= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-RUN-TO.png - - vAqPppTiI+x8KYLdk8fsWDNYffw= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-START.png - - Nw/BC82aGsOURM3On1USt+c/x9s= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-INTO.png - - QBcaZEtqMeAoDEbAZGN7wi3Vr3w= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OUT.png - - Jipy47oGAITIrfxIh3a5Lkjr580= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-STEP-OVER.png - - UYtDEVYffC4oks+3oAxFpKvZ6C4= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-STOP.png - - jjFhKHDdOMLQE3icv91dem8yaUk= - - ZeroBraneStudio/zbstudio/res/24/DEBUG-WATCH.png - - o+7jL3CZWlUl1EYPRvPT6UGAxfE= - - ZeroBraneStudio/zbstudio/res/24/DIR-SETUP-FILE.png - - n/elc2Rh1sgY9b32E1VI9rkgdjw= - - ZeroBraneStudio/zbstudio/res/24/DIR-SETUP.png - - tumK7h9wJnId59d9pXxlzkoLXAw= - - ZeroBraneStudio/zbstudio/res/24/FILE-NEW.png - - oNY7kU1GdAof05q8+/eeoPqJnv4= - - ZeroBraneStudio/zbstudio/res/24/FILE-OPEN.png - - SrBrom89SebwxDzIY3IhUlPDHbY= - - ZeroBraneStudio/zbstudio/res/24/FILE-SAVE-ALL.png - - GjlYy15t2GtoN+6TPCsqx+HFYTo= - - ZeroBraneStudio/zbstudio/res/24/FILE-SAVE.png - - uLF8oVyF+wQWYoyB78ONExHSiWc= - - ZeroBraneStudio/zbstudio/res/24/FIND-AND-REPLACE.png - - f+MDQo7Gd3gaHMo5H3uSAsxVJWg= - - ZeroBraneStudio/zbstudio/res/24/FIND-IN-FILES.png - - 3ov01Oog4b3EftWtkn6WCpgNcWs= - - ZeroBraneStudio/zbstudio/res/24/FIND.png - - cL8ihHzlZMa9BOs5kTbevXjQB34= - - ZeroBraneStudio/zbstudio/res/24/LICENSE - - buGhQcQKMCQu+SlaT8xIchLwsqk= - - ZeroBraneStudio/zbstudio/res/24/RUN-NOW.png - - JrTQpmABCCBgbAzsI3FxKD5Oxg0= - - ZeroBraneStudio/zbstudio/res/24/RUN.png - - tsAEEVOVCsp/BD6+RIsuWjmYBlk= - - ZeroBraneStudio/zbstudio/res/estrela.png - - /Y9/c/qkhDyQl4+mBtBSYKKF83A= - - ZeroBraneStudio/zbstudio/res/zbstudio.ico - - PqIN+8SytNAdrGKMi45ZXv4IytA= - - ZeroBraneStudio/zbstudio/res/zerobrane.png - - vLsBc4ANiG934i9y3ikmRX5QSUM= - - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeSignature b/android/tools/zbstudio.app/Contents/_CodeSignature/CodeSignature deleted file mode 100644 index 0e9c5d4..0000000 Binary files a/android/tools/zbstudio.app/Contents/_CodeSignature/CodeSignature and /dev/null differ diff --git a/assets/scripts/controls.lua b/assets/scripts/controls.lua index a9f23cb..3a78bca 100644 --- a/assets/scripts/controls.lua +++ b/assets/scripts/controls.lua @@ -1,4 +1,5 @@ local controls = {} +local buttons = {} function controls.load(game) controls.padding = 50 @@ -8,19 +9,7 @@ function controls.load(game) end function controls.update(dt) - control_up, control_right, control_left, control_quit = false, false, false, false - -- Keyboard - if love.keyboard.isDown('escape') or love.keyboard.isDown('q') then - control_quit = true - end - if love.keyboard.isDown('right') then - control_right = true - elseif love.keyboard.isDown('left') then - control_left = true - end - if love.keyboard.isDown('up') then - control_up = true - end + -- Keyboard -- Mouse if love.mouse.isDown(1) then local x, y = love.mouse.getPosition() @@ -41,4 +30,28 @@ function controls.draw() love.graphics.draw(controls.img_right, controls.right_x, controls.right_y) end +function controls.keypressed(key, scancode, isrepeat) + if key == 'escape' or key == 'q' then + CONTROL_QUIT = true + end + if key == 'right' then + CONTROL_RIGHT = true + elseif key == 'left' then + CONTROL_LEFT = true + end + if key == 'up' then + CONTROL_UP = true + end +end + +function controls.keyreleased(key, scancode) + CONTROL_UP, CONTROL_RIGHT, CONTROL_LEFT, CONTROL_QUIT = false, false, false, false +end + +function controls.mousepressed(x, y, button, istouch) +end + +function controls.mousereleased(x, y, button, istouch) +end + return controls \ No newline at end of file diff --git a/assets/scripts/game.lua b/assets/scripts/game.lua index 810784c..38ae59d 100644 --- a/assets/scripts/game.lua +++ b/assets/scripts/game.lua @@ -14,8 +14,6 @@ function game.load() local gravity = 2 love.physics.setMeter(world_meter) -- Height earth in meters game.world = love.physics.newWorld(0, gravity * world_meter, true) -- Make earth - -- Collisions - --game.collisions = HC.new(150) end return game \ No newline at end of file diff --git a/assets/scripts/spaceship.lua b/assets/scripts/spaceship.lua index 541ab7c..cefdc97 100644 --- a/assets/scripts/spaceship.lua +++ b/assets/scripts/spaceship.lua @@ -80,18 +80,18 @@ function spaceship.update(dt, game) -- Explosion explosion.animation:update(dt) -- Controls - if control_up then + if CONTROL_UP then body.body:applyForce(0, -body.power) press_button = true end - if control_right then + if CONTROL_RIGHT then body.body:applyForce(body.power, 0) press_button = true - elseif control_left then + elseif CONTROL_LEFT then body.body:applyForce(-body.power, 0) press_button = true end - if control_quit then + if CONTROL_QUIT then love.event.push('quit') end -- Collision diff --git a/main.lua b/main.lua index 332178c..a1a94c0 100644 --- a/main.lua +++ b/main.lua @@ -40,10 +40,18 @@ function love.draw() end -- CONTROLS -function love.keyreleased(key) - -- sounds.keyreleased(key) +function love.keypressed(key, scancode, isrepeat) + controls.keypressed(key, scancode, isrepeat) end -function love.mousereleased(key) - -- sounds.mousereleased(key) +function love.keyreleased(key, scancode) + controls.keyreleased(key, scancode) +end + +function love.mousepressed(x, y, button, istouch) + controls.mousepressed(x, y, button, istouch) +end + +function love.mousereleased(x, y, button, istouch) + controls.mousereleased(x, y, button, istouch) end \ No newline at end of file