├── .github └── workflows │ └── stale.yml ├── .gitignore ├── CHANGES.md ├── Code_of_Conduct.md ├── LATESTVERSION ├── Makefile ├── Mjolnir.xcodeproj └── project.pbxproj ├── Mjolnir ├── AutoUpdaterWindow.xib ├── ConsoleWindow.xib ├── Credits.rtf ├── Images.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png ├── MJAccessibilityUtils.h ├── MJAccessibilityUtils.m ├── MJAppDelegate.m ├── MJAutoLaunch.h ├── MJAutoLaunch.m ├── MJAutoUpdaterWindowController.h ├── MJAutoUpdaterWindowController.m ├── MJConfigUtils.h ├── MJConfigUtils.m ├── MJConsoleWindowController.h ├── MJConsoleWindowController.m ├── MJDockIcon.h ├── MJDockIcon.m ├── MJFileUtils.h ├── MJFileUtils.m ├── MJLua.h ├── MJLua.m ├── MJMenuIcon.h ├── MJMenuIcon.m ├── MJPreferencesWindowController.h ├── MJPreferencesWindowController.m ├── MJSecurityUtils.h ├── MJSecurityUtils.m ├── MJUpdate.h ├── MJUpdate.m ├── MJUpdateChecker.h ├── MJUpdateChecker.m ├── MJUserNotificationManager.h ├── MJUserNotificationManager.m ├── MJVersionUtils.h ├── MJVersionUtils.m ├── MainMenu.xib ├── Mjolnir-Info.plist ├── Mjolnir-Prefix.pch ├── MjolnirRestarter │ └── main.m ├── PreferencesWindow.xib ├── lua │ ├── lapi.c │ ├── lapi.h │ ├── lauxlib.c │ ├── lauxlib.h │ ├── lbaselib.c │ ├── lbitlib.c │ ├── lcode.c │ ├── lcode.h │ ├── lcorolib.c │ ├── lctype.c │ ├── lctype.h │ ├── ldblib.c │ ├── ldebug.c │ ├── ldebug.h │ ├── ldo.c │ ├── ldo.h │ ├── ldump.c │ ├── lfunc.c │ ├── lfunc.h │ ├── lgc.c │ ├── lgc.h │ ├── linit.c │ ├── liolib.c │ ├── llex.c │ ├── llex.h │ ├── llimits.h │ ├── lmathlib.c │ ├── lmem.c │ ├── lmem.h │ ├── loadlib.c │ ├── lobject.c │ ├── lobject.h │ ├── lopcodes.c │ ├── lopcodes.h │ ├── loslib.c │ ├── lparser.c │ ├── lparser.h │ ├── lprefix.h │ ├── lstate.c │ ├── lstate.h │ ├── lstring.c │ ├── lstring.h │ ├── lstrlib.c │ ├── ltable.c │ ├── ltable.h │ ├── ltablib.c │ ├── ltm.c │ ├── ltm.h │ ├── lua.c │ ├── lua.h │ ├── lua.hpp │ ├── luac.c │ ├── luaconf.h │ ├── lualib.h │ ├── lundump.c │ ├── lundump.h │ ├── lutf8lib.c │ ├── lvm.c │ ├── lvm.h │ ├── lzio.c │ └── lzio.h ├── setup.lua ├── statusicon.png ├── statusicon@2x.png └── variables.h ├── README.md ├── docs ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Makefile ├── README.md ├── bin │ ├── download │ ├── gencomments │ ├── genhtml │ ├── genjson │ └── gensql └── templates │ ├── Mjolnir.docset │ ├── Contents │ │ ├── Info.plist │ │ └── Resources │ │ │ └── Documents │ │ │ └── .gitkeep │ ├── icon.png │ └── icon@2x.png │ ├── ext.html.erb │ ├── index.html.erb │ └── index.md ├── mods ├── LICENSE.md ├── README.md ├── alert │ ├── .gitignore │ ├── Alert.xcodeproj │ │ └── project.pbxproj │ ├── alert.m │ └── mjolnir.alert-0.2-1.rockspec ├── application │ ├── .gitignore │ ├── Application.xcodeproj │ │ └── project.pbxproj │ ├── application.h │ ├── application.lua │ ├── application.m │ ├── mjolnir.application-0.3-1.rockspec │ ├── window.h │ ├── window.lua │ └── window.m ├── fnutils │ ├── .gitignore │ ├── fnutils.lua │ └── mjolnir.fnutils-0.1-1.rockspec ├── geometry │ ├── .gitignore │ ├── Geometry.xcodeproj │ │ └── project.pbxproj │ ├── geometry.lua │ ├── geometry.m │ └── mjolnir.geometry-0.2-1.rockspec ├── hotkey │ ├── .gitignore │ ├── Hotkey.xcodeproj │ │ └── project.pbxproj │ ├── hotkey.lua │ ├── hotkey.m │ └── mjolnir.hotkey-0.3-1.rockspec ├── keycodes │ ├── .gitignore │ ├── Keycodes.xcodeproj │ │ └── project.pbxproj │ ├── keycodes.lua │ ├── keycodes.m │ └── mjolnir.keycodes-0.2-1.rockspec └── screen │ ├── .gitignore │ ├── Screen.xcodeproj │ └── project.pbxproj │ ├── mjolnir.screen-0.2-1.rockspec │ ├── screen.lua │ └── screen.m ├── sample-plugin ├── .gitignore ├── README.md ├── foobar.lua ├── foobar.m └── mjolnir.yourid.foobar-0.1-1.rockspec └── screenshots ├── dict.gif └── grid.gif /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v1 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | stale-issue-message: 'Stale issue message' 17 | stale-pr-message: 'Stale pull request message' 18 | stale-issue-label: 'no-issue-activity' 19 | stale-pr-label: 'no-pr-activity' 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | /Mjolnir.app 21 | /Mjolnir*.zip 22 | /Mjolnir*.tgz 23 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ### 0.3.1 2 | 3 | - Renamed global `mj` to `mjolnir` 4 | 5 | ### 0.3 6 | 7 | - The UI has changed drastically. Expect nothing to be in the same 8 | place or look the same. Pretend it's a brand new app. 9 | - Extensions are now handled by LuaRocks instead of by the app itself. 10 | - The "core" namespace has been renamed to "mj". 11 | - The 'mj.window' module now ships with the 'mj.application' LuaRocks 12 | package since they depend on each other. 13 | - `mj.screen:frame_without_dock_or_menu()` is now called `mj.screen:frame()` 14 | - `mj.screen:frame_including_dock_and_menu()` is now called `mj.screen:fullframe()` 15 | -------------------------------------------------------------------------------- /Code_of_Conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | 1. Don't make me have to add more things to this. 4 | -------------------------------------------------------------------------------- /LATESTVERSION: -------------------------------------------------------------------------------- 1 | 0.4.3 2 | https://github.com/sdegutis/mjolnir/releases/download/0.4.3/Mjolnir-0.4.3.tgz 3 | MCwCFG1Wl/1LRJC9MYi/pON1hHGG7iWNAhRqAwvqHNuTZw0tcqf98ZrFx/Wo/Q== 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION = $(shell defaults read `pwd`/Mjolnir/Mjolnir-Info CFBundleVersion) 2 | APPFILE = Mjolnir.app 3 | TGZFILE = Mjolnir-$(VERSION).tgz 4 | ZIPFILE = Mjolnir-$(VERSION).zip 5 | VERSIONFILE = LATESTVERSION 6 | 7 | release: $(TGZFILE) $(ZIPFILE) $(VERSIONFILE) 8 | 9 | $(APPFILE): $(shell find Mjolnir -type f) 10 | rm -rf $@ 11 | xcodebuild clean build > /dev/null 12 | cp -R build/Release/Mjolnir.app $@ 13 | 14 | $(TGZFILE): $(APPFILE) 15 | tar -czf $@ $< 16 | 17 | $(ZIPFILE): $(APPFILE) 18 | zip -qr $@ $< 19 | 20 | $(VERSIONFILE): $(TGZFILE) 21 | test -n "$(KEYFILE)" 22 | echo $(VERSION) > $@ 23 | echo https://github.com/sdegutis/mjolnir/releases/download/$(VERSION)/Mjolnir-$(VERSION).tgz >> $@ 24 | openssl dgst -sha1 -binary < $(TGZFILE) | openssl dgst -dss1 -sign $(KEYFILE) | openssl enc -base64 >> $@ 25 | 26 | clean: 27 | rm -rf $(APPFILE) $(TGZFILE) $(ZIPFILE) 28 | 29 | .PHONY: release clean 30 | -------------------------------------------------------------------------------- /Mjolnir/ConsoleWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Mjolnir/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \margl1440\margr1440\vieww22840\viewh13760\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc 6 | 7 | \f0\fs22 \cf0 \ 8 | {\field{\*\fldinst{HYPERLINK "http://mjolnir.io"}}{\fldrslt mjolnir.io}}\ 9 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural 10 | \cf0 \ 11 | 12 | \b App Icon 13 | \b0 \ 14 | \ 15 | Created by {\field{\*\fldinst{HYPERLINK "https://github.com/jasonm23/"}}{\fldrslt jasonm23}}\ 16 | \ 17 | 18 | \b Lua 5.1 19 | \b0 \ 20 | \ 21 | Copyright (c) 1994-2014 {\field{\*\fldinst{HYPERLINK "http://Lua.org"}}{\fldrslt Lua.org}}, PUC-Rio.\ 22 | \ 23 | Permission is hereby granted, free of charge, to any person obtaining\ 24 | a copy of this software and associated documentation files (the\ 25 | "Software"), to deal in the Software without restriction, including\ 26 | without limitation the rights to use, copy, modify, merge, publish,\ 27 | distribute, sublicense, and/or sell copies of the Software, and to\ 28 | permit persons to whom the Software is furnished to do so, subject to\ 29 | the following conditions:\ 30 | \ 31 | The above copyright notice and this permission notice shall be\ 32 | included in all copies or substantial portions of the Software.\ 33 | \ 34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\ 35 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\ 36 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\ 37 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\ 38 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\ 39 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\ 40 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.} -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Mjolnir/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /Mjolnir/MJAccessibilityUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | BOOL MJAccessibilityIsEnabled(void); 4 | void MJAccessibilityOpenPanel(void); 5 | -------------------------------------------------------------------------------- /Mjolnir/MJAccessibilityUtils.m: -------------------------------------------------------------------------------- 1 | #import "MJAccessibilityUtils.h" 2 | 3 | extern Boolean AXIsProcessTrustedWithOptions(CFDictionaryRef options) __attribute__((weak_import)); 4 | extern CFStringRef kAXTrustedCheckOptionPrompt __attribute__((weak_import)); 5 | 6 | 7 | BOOL MJAccessibilityIsEnabled(void) { 8 | if (AXIsProcessTrustedWithOptions != NULL) 9 | return AXIsProcessTrustedWithOptions(NULL); 10 | else 11 | return AXAPIEnabled(); 12 | } 13 | 14 | void MJAccessibilityOpenPanel(void) { 15 | if (AXIsProcessTrustedWithOptions != NULL) { 16 | AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)@{(__bridge id)kAXTrustedCheckOptionPrompt: @YES}); 17 | } 18 | else { 19 | static NSString* script = @"tell application \"System Preferences\"\nactivate\nset current pane to pane \"com.apple.preference.universalaccess\"\nend tell"; 20 | [[[NSAppleScript alloc] initWithSource:script] executeAndReturnError:nil]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Mjolnir/MJAppDelegate.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MJConsoleWindowController.h" 3 | #import "MJPreferencesWindowController.h" 4 | #import "MJUpdateChecker.h" 5 | #import "MJDockIcon.h" 6 | #import "MJMenuIcon.h" 7 | #import "MJLua.h" 8 | #import "MJVersionUtils.h" 9 | #import "MJConfigUtils.h" 10 | #import "MJFileUtils.h" 11 | #import "variables.h" 12 | 13 | @interface MJAppDelegate : NSObject 14 | @property IBOutlet NSMenu* menuBarMenu; 15 | @end 16 | 17 | @implementation MJAppDelegate 18 | 19 | static BOOL MJFirstRunForCurrentVersion(void) { 20 | NSString* key = [NSString stringWithFormat:@"%@_%d", MJHasRunAlreadyKey, MJVersionFromThisApp()]; 21 | 22 | BOOL firstRun = ![[NSUserDefaults standardUserDefaults] boolForKey:key]; 23 | 24 | if (firstRun) 25 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:key]; 26 | 27 | return firstRun; 28 | } 29 | 30 | - (BOOL) applicationShouldHandleReopen:(NSApplication*)theApplication hasVisibleWindows:(BOOL)hasVisibleWindows { 31 | [[MJConsoleWindowController singleton] showWindow: nil]; 32 | return NO; 33 | } 34 | 35 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 36 | MJEnsureDirectoryExists(MJConfigDir()); 37 | [[NSFileManager defaultManager] changeCurrentDirectoryPath:MJConfigDir()]; 38 | 39 | [self registerDefaultDefaults]; 40 | MJMenuIconSetup(self.menuBarMenu); 41 | MJDockIconSetup(); 42 | MJUpdateCheckerSetup(); 43 | [[MJConsoleWindowController singleton] setup]; 44 | MJLuaSetup(); 45 | 46 | if (MJFirstRunForCurrentVersion()) 47 | [[MJPreferencesWindowController singleton] showWindow: nil]; 48 | } 49 | 50 | - (void) registerDefaultDefaults { 51 | [[NSUserDefaults standardUserDefaults] 52 | registerDefaults: @{MJCheckForUpdatesKey: @YES, 53 | MJShowDockIconKey: @YES, 54 | MJShowMenuIconKey: @NO, 55 | MJCheckForUpdatesIntervalKey: @(60.0 * 60.0 * 24.0)}]; 56 | } 57 | 58 | - (IBAction) reloadConfig:(id)sender { 59 | MJLuaSetup(); 60 | } 61 | 62 | - (IBAction) showConsoleWindow:(id)sender { 63 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 64 | [[MJConsoleWindowController singleton] showWindow: nil]; 65 | } 66 | 67 | - (IBAction) showPreferencesWindow:(id)sender { 68 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 69 | [[MJPreferencesWindowController singleton] showWindow: nil]; 70 | } 71 | 72 | - (IBAction) showAboutPanel:(id)sender { 73 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 74 | [[NSApplication sharedApplication] orderFrontStandardAboutPanel: nil]; 75 | } 76 | 77 | - (IBAction) checkForUpdates:(id)sender { 78 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 79 | MJUpdateCheckerCheckVerbosely(); 80 | } 81 | 82 | - (IBAction) openConfig:(id)sender { 83 | NSString* path = MJConfigFileFullPath(); 84 | 85 | if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { 86 | [[NSFileManager defaultManager] createFileAtPath:path 87 | contents:[NSData data] 88 | attributes:nil]; 89 | } 90 | 91 | [[NSWorkspace sharedWorkspace] openFile: path]; 92 | } 93 | 94 | @end 95 | 96 | int main(int argc, const char * argv[]) { 97 | return NSApplicationMain(argc, argv); 98 | } 99 | -------------------------------------------------------------------------------- /Mjolnir/MJAutoLaunch.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | BOOL MJAutoLaunchGet(void); 4 | void MJAutoLaunchSet(BOOL opensAtLogin); 5 | -------------------------------------------------------------------------------- /Mjolnir/MJAutoLaunch.m: -------------------------------------------------------------------------------- 1 | #import "MJAutoLaunch.h" 2 | 3 | static LSSharedFileListRef shared_file_list() { 4 | static LSSharedFileListRef list; 5 | static dispatch_once_t onceToken; 6 | dispatch_once(&onceToken, ^{ 7 | list = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 8 | }); 9 | return list; 10 | } 11 | 12 | BOOL MJAutoLaunchGet(void) { 13 | NSURL *appURL = [[[NSBundle mainBundle] bundleURL] fileReferenceURL]; 14 | 15 | UInt32 seed; 16 | NSArray *sharedFileListArray = (__bridge_transfer NSArray*)LSSharedFileListCopySnapshot(shared_file_list(), &seed); 17 | for (id item in sharedFileListArray) { 18 | LSSharedFileListItemRef sharedFileItem = (__bridge LSSharedFileListItemRef)item; 19 | CFURLRef url = NULL; 20 | 21 | OSStatus result = LSSharedFileListItemResolve(sharedFileItem, 0, &url, NULL); 22 | if (result == noErr && url != NULL) { 23 | BOOL foundIt = [appURL isEqual: [(__bridge NSURL*)url fileReferenceURL]]; 24 | 25 | CFRelease(url); 26 | 27 | if (foundIt) { 28 | return YES; 29 | } 30 | } 31 | } 32 | 33 | return NO; 34 | } 35 | 36 | void MJAutoLaunchSet(BOOL opensAtLogin) { 37 | NSURL *appURL = [[[NSBundle mainBundle] bundleURL] fileReferenceURL]; 38 | 39 | if (opensAtLogin) { 40 | LSSharedFileListItemRef result = LSSharedFileListInsertItemURL(shared_file_list(), 41 | kLSSharedFileListItemLast, 42 | NULL, 43 | NULL, 44 | (__bridge CFURLRef)appURL, 45 | NULL, 46 | NULL); 47 | CFRelease(result); 48 | } 49 | else { 50 | UInt32 seed; 51 | NSArray *sharedFileListArray = (__bridge_transfer NSArray*)LSSharedFileListCopySnapshot(shared_file_list(), &seed); 52 | for (id item in sharedFileListArray) { 53 | LSSharedFileListItemRef sharedFileItem = (__bridge LSSharedFileListItemRef)item; 54 | CFURLRef url = NULL; 55 | 56 | OSStatus result = LSSharedFileListItemResolve(sharedFileItem, 0, &url, NULL); 57 | if (result == noErr && url != nil) { 58 | if ([appURL isEqual: [(__bridge NSURL*)url fileReferenceURL]]) 59 | LSSharedFileListItemRemove(shared_file_list(), sharedFileItem); 60 | 61 | CFRelease(url); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Mjolnir/MJAutoUpdaterWindowController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MJUpdate.h" 3 | 4 | @interface MJAutoUpdaterWindowController : NSWindowController 5 | 6 | @property MJUpdate* update; 7 | @property NSString* error; 8 | 9 | - (void) showCheckingPage; 10 | - (void) showUpToDatePage; 11 | - (void) showFoundPage; 12 | - (void) showErrorPage; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Mjolnir/MJAutoUpdaterWindowController.m: -------------------------------------------------------------------------------- 1 | #import "MJAutoUpdaterWindowController.h" 2 | #import "variables.h" 3 | 4 | @interface MJAutoUpdaterWindowController () 5 | 6 | @property (weak) IBOutlet NSTabView* tabView; 7 | @property (weak) IBOutlet NSProgressIndicator* checkingProgressBar; 8 | @property (weak) IBOutlet NSProgressIndicator* installationProgressBar; 9 | @property (weak) IBOutlet NSButton* showChangeLogButton; 10 | 11 | @end 12 | 13 | @implementation MJAutoUpdaterWindowController 14 | 15 | - (NSString*) windowNibName { 16 | return @"AutoUpdaterWindow"; 17 | } 18 | 19 | - (IBAction) showReleaseNotes:(id)sender { 20 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:MJReleaseNotesURL]]; 21 | } 22 | 23 | - (void) windowDidLoad { 24 | [super windowDidLoad]; 25 | [self.checkingProgressBar startAnimation:self]; 26 | [self.installationProgressBar startAnimation:self]; 27 | [self makeFakeLink]; 28 | } 29 | 30 | - (void) makeFakeLink { 31 | NSRange r = NSMakeRange(0, [[self.showChangeLogButton title] length]); 32 | NSMutableAttributedString* title = [[self.showChangeLogButton attributedTitle] mutableCopy]; 33 | [title addAttribute:NSForegroundColorAttributeName value:[NSColor blueColor] range: r]; 34 | [title addAttribute:NSUnderlineStyleAttributeName value:@1 range: r]; 35 | [self.showChangeLogButton setAttributedTitle:title]; 36 | } 37 | 38 | - (IBAction) dismiss:(id)sender { 39 | [self close]; 40 | } 41 | 42 | - (IBAction) cancel:(id)sender { 43 | [self close]; 44 | } 45 | 46 | - (IBAction) install:(id)sender { 47 | [self showInstallingPage]; 48 | [self.update install:^(NSString *error, NSString *reason) { 49 | self.error = [NSString stringWithFormat:@"%@ (%@)", error, reason]; 50 | [self showErrorPage]; 51 | }]; 52 | } 53 | 54 | - (IBAction) visitDownloadPage:(id)sender { 55 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:MJDownloadPage]]; 56 | [self close]; 57 | } 58 | 59 | - (void) showTab:(int)n { 60 | NSDisableScreenUpdates(); 61 | if (![[self window] isVisible]) 62 | [[self window] center]; 63 | [[self window] makeKeyAndOrderFront: self]; 64 | [self.tabView selectTabViewItemAtIndex:n]; 65 | NSEnableScreenUpdates(); 66 | } 67 | 68 | - (void) showCheckingPage { 69 | self.error = nil; 70 | [self showTab: 0]; 71 | } 72 | 73 | - (void) showUpToDatePage { 74 | self.error = nil; 75 | [self showTab: 1]; 76 | } 77 | 78 | - (void) showFoundPage { 79 | self.error = nil; 80 | [self showTab: 2]; 81 | } 82 | 83 | - (void) showErrorPage { 84 | [self showTab: 3]; 85 | } 86 | 87 | - (void) showInstallingPage { 88 | self.error = nil; 89 | [self showTab: 4]; 90 | } 91 | 92 | @end 93 | 94 | @interface MJLinkButton : NSButton 95 | @end 96 | 97 | @implementation MJLinkButton 98 | 99 | - (void)resetCursorRects { 100 | [self addCursorRect:[self bounds] 101 | cursor:[NSCursor pointingHandCursor]]; 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Mjolnir/MJConfigUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NSString* MJConfigDir(void); 4 | NSString* MJConfigFileFullPath(void); 5 | -------------------------------------------------------------------------------- /Mjolnir/MJConfigUtils.m: -------------------------------------------------------------------------------- 1 | #import "MJConfigUtils.h" 2 | #import "variables.h" 3 | 4 | NSString* MJConfigDir(void) { 5 | return [MJConfigFileFullPath() stringByDeletingLastPathComponent]; 6 | } 7 | 8 | NSString* MJConfigFileFullPath(void) { 9 | return [MJConfigFile stringByStandardizingPath]; 10 | } 11 | -------------------------------------------------------------------------------- /Mjolnir/MJConsoleWindowController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MJConsoleWindowController : NSWindowController 4 | 5 | + (instancetype) singleton; 6 | - (void) setup; 7 | 8 | @end 9 | 10 | BOOL MJConsoleWindowAlwaysOnTop(void); 11 | void MJConsoleWindowSetAlwaysOnTop(BOOL alwaysOnTop); 12 | -------------------------------------------------------------------------------- /Mjolnir/MJConsoleWindowController.m: -------------------------------------------------------------------------------- 1 | #import "MJConsoleWindowController.h" 2 | #import "MJLua.h" 3 | #import "variables.h" 4 | 5 | #define MJColorForStdout [NSColor colorWithCalibratedHue:0.88 saturation:1.0 brightness:0.6 alpha:1.0] 6 | #define MJColorForCommand [NSColor blackColor] 7 | #define MJColorForResult [NSColor colorWithCalibratedHue:0.54 saturation:1.0 brightness:0.7 alpha:1.0] 8 | 9 | @interface MJConsoleWindowController () 10 | 11 | @property NSMutableArray* history; 12 | @property NSInteger historyIndex; 13 | @property IBOutlet NSTextView* outputView; 14 | @property (weak) IBOutlet NSTextField* inputField; 15 | @property NSMutableArray* preshownStdouts; 16 | 17 | @end 18 | 19 | typedef NS_ENUM(NSUInteger, MJReplLineType) { 20 | MJReplLineTypeCommand, 21 | MJReplLineTypeResult, 22 | MJReplLineTypeStdout, 23 | }; 24 | 25 | @implementation MJConsoleWindowController 26 | 27 | - (NSString*) windowNibName { 28 | return @"ConsoleWindow"; 29 | } 30 | 31 | + (instancetype) singleton { 32 | static MJConsoleWindowController* s; 33 | static dispatch_once_t onceToken; 34 | dispatch_once(&onceToken, ^{ 35 | s = [[MJConsoleWindowController alloc] init]; 36 | }); 37 | return s; 38 | } 39 | 40 | - (void) setup { 41 | self.preshownStdouts = [NSMutableArray array]; 42 | MJLuaSetupLogHandler(^(NSString* str){ 43 | if (self.outputView) { 44 | [self appendString:str type:MJReplLineTypeStdout]; 45 | [self.outputView scrollToEndOfDocument:self]; 46 | } 47 | else { 48 | [self.preshownStdouts addObject:str]; 49 | } 50 | }); 51 | [self reflectDefaults]; 52 | } 53 | 54 | - (void) reflectDefaults { 55 | [[self window] setLevel: MJConsoleWindowAlwaysOnTop() ? NSFloatingWindowLevel : NSNormalWindowLevel]; 56 | } 57 | 58 | - (void) windowDidLoad { 59 | [[self window] center]; 60 | 61 | self.history = [NSMutableArray array]; 62 | [self.outputView setEditable:NO]; 63 | [self.outputView setSelectable:YES]; 64 | 65 | [self appendString:@"" 66 | "Welcome to the Mjolnir Console!\n" 67 | "You can run any Lua code in here.\n\n" 68 | type:MJReplLineTypeStdout]; 69 | 70 | for (NSString* str in self.preshownStdouts) 71 | [self appendString:str type:MJReplLineTypeStdout]; 72 | 73 | [self.outputView scrollToEndOfDocument:self]; 74 | self.preshownStdouts = nil; 75 | } 76 | 77 | - (void) appendString:(NSString*)str type:(MJReplLineType)type { 78 | NSColor* color = nil; 79 | switch (type) { 80 | case MJReplLineTypeStdout: color = MJColorForStdout; break; 81 | case MJReplLineTypeCommand: color = MJColorForCommand; break; 82 | case MJReplLineTypeResult: color = MJColorForResult; break; 83 | } 84 | 85 | NSDictionary* attrs = @{NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:12.0], NSForegroundColorAttributeName: color}; 86 | NSAttributedString* attrstr = [[NSAttributedString alloc] initWithString:str attributes:attrs]; 87 | [[self.outputView textStorage] appendAttributedString:attrstr]; 88 | } 89 | 90 | - (NSString*) run:(NSString*)command { 91 | return MJLuaRunString(command); 92 | } 93 | 94 | - (IBAction) tryMessage:(NSTextField*)sender { 95 | NSString* command = [sender stringValue]; 96 | [self appendString:[NSString stringWithFormat:@"\n> %@\n", command] type:MJReplLineTypeCommand]; 97 | 98 | NSString* result = [self run:command]; 99 | [self appendString:[NSString stringWithFormat:@"%@\n", result] type:MJReplLineTypeResult]; 100 | 101 | [sender setStringValue:@""]; 102 | [self saveToHistory:command]; 103 | [self.outputView scrollToEndOfDocument:self]; 104 | } 105 | 106 | - (void) saveToHistory:(NSString*)cmd { 107 | [self.history addObject:cmd]; 108 | self.historyIndex = [self.history count]; 109 | [self useCurrentHistoryIndex]; 110 | } 111 | 112 | - (void) goPrevHistory { 113 | self.historyIndex = MAX(self.historyIndex - 1, 0); 114 | [self useCurrentHistoryIndex]; 115 | } 116 | 117 | - (void) goNextHistory { 118 | self.historyIndex = MIN(self.historyIndex + 1, [self.history count]); 119 | [self useCurrentHistoryIndex]; 120 | } 121 | 122 | - (void) useCurrentHistoryIndex { 123 | if (self.historyIndex == [self.history count]) 124 | [self.inputField setStringValue: @""]; 125 | else 126 | [self.inputField setStringValue: [self.history objectAtIndex:self.historyIndex]]; 127 | 128 | NSText* editor = [[self.inputField window] fieldEditor:YES forObject:self.inputField]; 129 | [editor moveToEndOfDocument:self]; 130 | } 131 | 132 | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { 133 | if (command == @selector(moveUp:)) { 134 | [self goPrevHistory]; 135 | return YES; 136 | } 137 | else if (command == @selector(moveDown:)) { 138 | [self goNextHistory]; 139 | return YES; 140 | } 141 | return NO; 142 | } 143 | 144 | BOOL MJConsoleWindowAlwaysOnTop(void) { 145 | return [[NSUserDefaults standardUserDefaults] boolForKey: MJKeepConsoleOnTopKey]; 146 | } 147 | 148 | void MJConsoleWindowSetAlwaysOnTop(BOOL alwaysOnTop) { 149 | [[NSUserDefaults standardUserDefaults] setBool:alwaysOnTop 150 | forKey:MJKeepConsoleOnTopKey]; 151 | [[MJConsoleWindowController singleton] reflectDefaults]; 152 | } 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /Mjolnir/MJDockIcon.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | void MJDockIconSetup(void); 4 | BOOL MJDockIconVisible(void); 5 | void MJDockIconSetVisible(BOOL visible); 6 | -------------------------------------------------------------------------------- /Mjolnir/MJDockIcon.m: -------------------------------------------------------------------------------- 1 | #import "MJDockIcon.h" 2 | #import "variables.h" 3 | 4 | static void reflect_defaults(void); 5 | 6 | void MJDockIconSetup(void) { 7 | reflect_defaults(); 8 | } 9 | 10 | BOOL MJDockIconVisible(void) { 11 | return [[NSUserDefaults standardUserDefaults] boolForKey:MJShowDockIconKey]; 12 | } 13 | 14 | void MJDockIconSetVisible(BOOL visible) { 15 | [[NSUserDefaults standardUserDefaults] setBool:visible 16 | forKey:MJShowDockIconKey]; 17 | reflect_defaults(); 18 | } 19 | 20 | static void reflect_defaults(void) { 21 | NSApplication* app = [NSApplication sharedApplication]; // NSApp is typed to 'id'; lame 22 | NSDisableScreenUpdates(); 23 | [app setActivationPolicy: MJDockIconVisible() ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory]; 24 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 25 | [app unhide: nil]; 26 | [app activateIgnoringOtherApps:YES]; 27 | NSEnableScreenUpdates(); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /Mjolnir/MJFileUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | void MJDownloadFile(NSString* url, void(^handler)(NSError* err, NSData* data)); 4 | NSString* MJCreateEmptyTempDirectory(NSString* prefix, NSError* __autoreleasing* error); 5 | BOOL MJUntar(NSData* tardata, NSString* intoDirectory, NSError*__autoreleasing* error); 6 | BOOL MJEnsureDirectoryExists(NSString* dir); 7 | -------------------------------------------------------------------------------- /Mjolnir/MJFileUtils.m: -------------------------------------------------------------------------------- 1 | #import "MJFileUtils.h" 2 | 3 | void MJDownloadFile(NSString* url, void(^handler)(NSError* err, NSData* data)) { 4 | NSURLRequest* req = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; 5 | [NSURLConnection sendAsynchronousRequest:req 6 | queue:[NSOperationQueue mainQueue] 7 | completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 8 | handler(connectionError, data); 9 | }]; 10 | } 11 | 12 | NSString* MJCreateEmptyTempDirectory(NSString* prefix, NSError* __autoreleasing* error) { 13 | NSString* relativeTemplate = [NSString stringWithFormat:@"%@XXXXXX", prefix]; 14 | const char* tempFileTemplate = [[NSTemporaryDirectory() stringByAppendingPathComponent:relativeTemplate] fileSystemRepresentation]; 15 | char* tempFileName = malloc(strlen(tempFileTemplate) + 1); 16 | strcpy(tempFileName, tempFileTemplate); 17 | 18 | NSString* path = nil; 19 | 20 | if (mkdtemp(tempFileName)) 21 | path = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileName length:strlen(tempFileName)]; 22 | else 23 | *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]; 24 | 25 | free(tempFileName); 26 | return path; 27 | } 28 | 29 | BOOL MJUntar(NSData* tardata, NSString* intoDirectory, NSError*__autoreleasing* error) { 30 | BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:intoDirectory withIntermediateDirectories:YES attributes:nil error:error]; 31 | if (!success) return NO; 32 | 33 | NSPipe* pipe = [NSPipe pipe]; 34 | NSTask* untar = [[NSTask alloc] init]; 35 | [untar setLaunchPath:@"/usr/bin/tar"]; 36 | [untar setArguments:@[@"-xzf-", @"-C", intoDirectory]]; 37 | [untar setStandardInput:pipe]; 38 | [untar launch]; 39 | [[pipe fileHandleForWriting] writeData:tardata]; 40 | [[pipe fileHandleForWriting] closeFile]; 41 | [untar waitUntilExit]; 42 | if ([untar terminationStatus]) { 43 | *error = [NSError errorWithDomain:@"tar" code:[untar terminationStatus] userInfo:@{NSLocalizedDescriptionKey: @"could not extract the tgz archive"}]; 44 | return NO; 45 | } 46 | 47 | return YES; 48 | } 49 | 50 | BOOL MJEnsureDirectoryExists(NSString* dir) { 51 | return [[NSFileManager defaultManager] createDirectoryAtPath:dir 52 | withIntermediateDirectories:YES 53 | attributes:nil 54 | error:NULL]; 55 | } 56 | -------------------------------------------------------------------------------- /Mjolnir/MJLua.h: -------------------------------------------------------------------------------- 1 | #import "lauxlib.h" 2 | #import "lualib.h" 3 | 4 | void MJLuaSetup(void); 5 | void MJLuaSetupLogHandler(void(^blk)(NSString* str)); 6 | NSString* MJLuaRunString(NSString* command); 7 | NSString* MJFindInitFile(void); 8 | -------------------------------------------------------------------------------- /Mjolnir/MJLua.m: -------------------------------------------------------------------------------- 1 | #import "MJLua.h" 2 | #import "MJConsoleWindowController.h" 3 | #import "MJUserNotificationManager.h" 4 | #import "MJConfigUtils.h" 5 | #import "variables.h" 6 | 7 | static lua_State* MJLuaState; 8 | static int evalfn; 9 | 10 | /// === mjolnir === 11 | /// 12 | /// Core Mjolnir functionality. 13 | 14 | static void(^loghandler)(NSString* str); 15 | void MJLuaSetupLogHandler(void(^blk)(NSString* str)) { 16 | loghandler = blk; 17 | } 18 | 19 | /// mjolnir.openconsole() 20 | /// Function 21 | /// Opens the Mjolnir Console window and focuses it. 22 | static int core_openconsole(lua_State* L) { 23 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 24 | [[MJConsoleWindowController singleton] showWindow: nil]; 25 | return 0; 26 | } 27 | 28 | /// mjolnir.reload() 29 | /// Function 30 | /// Reloads your init-file in a fresh Lua environment. 31 | static int core_reload(lua_State* L) { 32 | dispatch_async(dispatch_get_main_queue(), ^{ 33 | MJLuaSetup(); 34 | }); 35 | return 0; 36 | } 37 | 38 | /// mjolnir.focus() 39 | /// Function 40 | /// Makes Mjolnir the foreground app. 41 | static int core_focus(lua_State* L) { 42 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 43 | return 0; 44 | } 45 | 46 | static int core_exit(lua_State* L) { 47 | if (lua_toboolean(L, 2)) 48 | lua_close(L); 49 | 50 | [[NSApplication sharedApplication] terminate: nil]; 51 | return 0; // lol 52 | } 53 | 54 | static int core_logmessage(lua_State* L) { 55 | size_t len; 56 | const char* s = lua_tolstring(L, 1, &len); 57 | NSString* str = [[NSString alloc] initWithData:[NSData dataWithBytes:s length:len] encoding:NSUTF8StringEncoding]; 58 | loghandler(str); 59 | return 0; 60 | } 61 | 62 | static int core_notify(lua_State* L) { 63 | size_t len; 64 | const char* s = lua_tolstring(L, 1, &len); 65 | NSString* str = [[NSString alloc] initWithData:[NSData dataWithBytes:s length:len] encoding:NSUTF8StringEncoding]; 66 | [[MJUserNotificationManager sharedManager] sendNotification:str handler:^{ 67 | [[MJConsoleWindowController singleton] showWindow: nil]; 68 | }]; 69 | return 0; 70 | } 71 | 72 | static luaL_Reg corelib[] = { 73 | {"openconsole", core_openconsole}, 74 | {"reload", core_reload}, 75 | {"focus", core_focus}, 76 | {"_exit", core_exit}, 77 | {"_logmessage", core_logmessage}, 78 | {"_notify", core_notify}, 79 | {} 80 | }; 81 | 82 | void MJLuaSetup(void) { 83 | if (MJLuaState) 84 | lua_close(MJLuaState); 85 | 86 | lua_State* L = MJLuaState = luaL_newstate(); 87 | luaL_openlibs(L); 88 | 89 | luaL_newlib(L, corelib); 90 | lua_setglobal(L, "mjolnir"); 91 | 92 | luaL_loadfile(L, [[[NSBundle mainBundle] pathForResource:@"setup" ofType:@"lua"] fileSystemRepresentation]); 93 | 94 | lua_pushstring(L, [MJConfigFile UTF8String]); 95 | lua_pushstring(L, [MJConfigFileFullPath() UTF8String]); 96 | lua_pushstring(L, [MJConfigDir() UTF8String]); 97 | lua_pushboolean(L, [[NSFileManager defaultManager] fileExistsAtPath: MJConfigFileFullPath()]); 98 | 99 | lua_pcall(L, 4, 1, 0); 100 | 101 | evalfn = luaL_ref(L, LUA_REGISTRYINDEX); 102 | } 103 | 104 | NSString* MJLuaRunString(NSString* command) { 105 | lua_State* L = MJLuaState; 106 | 107 | lua_rawgeti(L, LUA_REGISTRYINDEX, evalfn); 108 | lua_pushstring(L, [command UTF8String]); 109 | lua_call(L, 1, 1); 110 | 111 | size_t len; 112 | const char* s = lua_tolstring(L, -1, &len); 113 | NSString* str = [[NSString alloc] initWithData:[NSData dataWithBytes:s length:len] encoding:NSUTF8StringEncoding]; 114 | lua_pop(L, 1); 115 | 116 | return str; 117 | } 118 | -------------------------------------------------------------------------------- /Mjolnir/MJMenuIcon.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | void MJMenuIconSetup(NSMenu* menu); 4 | BOOL MJMenuIconVisible(void); 5 | void MJMenuIconSetVisible(BOOL visible); 6 | -------------------------------------------------------------------------------- /Mjolnir/MJMenuIcon.m: -------------------------------------------------------------------------------- 1 | #import "MJMenuIcon.h" 2 | #import "variables.h" 3 | 4 | static void reflect_defaults(void); 5 | 6 | static NSStatusItem* statusItem; 7 | static NSMenu* menuItemMenu; 8 | 9 | void MJMenuIconSetup(NSMenu* menu) { 10 | menuItemMenu = menu; 11 | reflect_defaults(); 12 | } 13 | 14 | BOOL MJMenuIconVisible(void) { 15 | return [[NSUserDefaults standardUserDefaults] boolForKey:MJShowMenuIconKey]; 16 | } 17 | 18 | void MJMenuIconSetVisible(BOOL visible) { 19 | [[NSUserDefaults standardUserDefaults] setBool:visible 20 | forKey:MJShowMenuIconKey]; 21 | reflect_defaults(); 22 | } 23 | 24 | static void reflect_defaults(void) { 25 | if (MJMenuIconVisible()) { 26 | NSImage* icon = [NSImage imageNamed:@"statusicon"]; 27 | [icon setTemplate:YES]; 28 | 29 | statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; 30 | [statusItem setImage:icon]; 31 | [statusItem setHighlightMode:YES]; 32 | [statusItem setMenu: menuItemMenu]; 33 | } 34 | else { 35 | if (statusItem) { 36 | [[NSStatusBar systemStatusBar] removeStatusItem: statusItem]; 37 | statusItem = nil; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Mjolnir/MJPreferencesWindowController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MJPreferencesWindowController : NSWindowController 4 | 5 | + (instancetype) singleton; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Mjolnir/MJPreferencesWindowController.m: -------------------------------------------------------------------------------- 1 | #import "MJPreferencesWindowController.h" 2 | #import "MJAutoLaunch.h" 3 | #import "MJLua.h" 4 | #import "MJUpdateChecker.h" 5 | #import "MJDockIcon.h" 6 | #import "MJMenuIcon.h" 7 | #import "MJAccessibilityUtils.h" 8 | #import "MJConsoleWindowController.h" 9 | #import "variables.h" 10 | 11 | #define MJSkipDockMenuIconProblemAlertKey @"MJSkipDockMenuIconProblemAlertKey" 12 | 13 | @interface MJPreferencesWindowController () 14 | 15 | @property (weak) IBOutlet NSButton* openAtLoginCheckbox; 16 | @property (weak) IBOutlet NSButton* showDockIconCheckbox; 17 | @property (weak) IBOutlet NSButton* showMenuIconCheckbox; 18 | @property (weak) IBOutlet NSButton* checkForUpdatesCheckbox; 19 | @property (weak) IBOutlet NSButton* keepConsoleOnTopCheckbox; 20 | 21 | @property BOOL isAccessibilityEnabled; 22 | 23 | @end 24 | 25 | @implementation MJPreferencesWindowController 26 | 27 | + (instancetype) singleton { 28 | static MJPreferencesWindowController* s; 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | s = [[MJPreferencesWindowController alloc] init]; 32 | }); 33 | return s; 34 | } 35 | 36 | - (void) showWindow:(id)sender { 37 | if (![[self window] isVisible]) 38 | [[self window] center]; 39 | [super showWindow: sender]; 40 | } 41 | 42 | - (NSString*) windowNibName { 43 | return @"PreferencesWindow"; 44 | } 45 | 46 | - (void)windowDidLoad { 47 | dispatch_async(dispatch_get_main_queue(), ^{ 48 | [self cacheIsAccessibilityEnabled]; 49 | }); 50 | 51 | [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(accessibilityChanged:) name:@"com.apple.accessibility.api" object:nil]; 52 | 53 | [self.openAtLoginCheckbox setState:MJAutoLaunchGet() ? NSOnState : NSOffState]; 54 | [self.showDockIconCheckbox setState: MJDockIconVisible() ? NSOnState : NSOffState]; 55 | [self.showMenuIconCheckbox setState: MJMenuIconVisible() ? NSOnState : NSOffState]; 56 | [self.checkForUpdatesCheckbox setState: MJUpdateCheckerEnabled() ? NSOnState : NSOffState]; 57 | [self.keepConsoleOnTopCheckbox setState: MJConsoleWindowAlwaysOnTop() ? NSOnState : NSOffState]; 58 | } 59 | 60 | - (void) accessibilityChanged:(NSNotification*)note { 61 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 62 | [self cacheIsAccessibilityEnabled]; 63 | }); 64 | } 65 | 66 | - (void) cacheIsAccessibilityEnabled { 67 | self.isAccessibilityEnabled = MJAccessibilityIsEnabled(); 68 | } 69 | 70 | - (NSString*) maybeEnableAccessibilityString { 71 | if (self.isAccessibilityEnabled) 72 | return @"Accessibility is enabled. You're all set!"; 73 | else 74 | return @"Enable Accessibility for best results."; 75 | } 76 | 77 | - (NSImage*) isAccessibilityEnabledImage { 78 | if (self.isAccessibilityEnabled) 79 | return [NSImage imageNamed:NSImageNameStatusAvailable]; 80 | else 81 | return [NSImage imageNamed:NSImageNameStatusPartiallyAvailable]; 82 | } 83 | 84 | + (NSSet*) keyPathsForValuesAffectingMaybeEnableAccessibilityString { 85 | return [NSSet setWithArray:@[@"isAccessibilityEnabled"]]; 86 | } 87 | 88 | + (NSSet*) keyPathsForValuesAffectingIsAccessibilityEnabledImage { 89 | return [NSSet setWithArray:@[@"isAccessibilityEnabled"]]; 90 | } 91 | 92 | - (IBAction) openAccessibility:(id)sender { 93 | MJAccessibilityOpenPanel(); 94 | } 95 | 96 | - (IBAction) toggleOpensAtLogin:(NSButton*)sender { 97 | BOOL enabled = [sender state] == NSOnState; 98 | MJAutoLaunchSet(enabled); 99 | } 100 | 101 | - (IBAction) toggleShowDockIcon:(NSButton*)sender { 102 | [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(actuallyToggleShowDockIcon) object:nil]; 103 | [self performSelector:@selector(actuallyToggleShowDockIcon) withObject:nil afterDelay:0.3]; 104 | } 105 | 106 | - (void) actuallyToggleShowDockIcon { 107 | BOOL enabled = [self.showDockIconCheckbox state] == NSOnState; 108 | MJDockIconSetVisible(enabled); 109 | [self maybeWarnAboutDockMenuProblem]; 110 | } 111 | 112 | - (IBAction) toggleMenuDockIcon:(NSButton*)sender { 113 | BOOL enabled = [sender state] == NSOnState; 114 | MJMenuIconSetVisible(enabled); 115 | [self maybeWarnAboutDockMenuProblem]; 116 | } 117 | 118 | - (IBAction) toggleCheckForUpdates:(NSButton*)sender { 119 | MJUpdateCheckerSetEnabled([sender state] == NSOnState); 120 | if (MJUpdateCheckerEnabled()) 121 | MJUpdateCheckerCheckSilently(); 122 | } 123 | 124 | - (IBAction) toggleKeepConsoleOnTop:(id)sender { 125 | MJConsoleWindowSetAlwaysOnTop([sender state] == NSOnState); 126 | } 127 | 128 | - (void) dockMenuProblemAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { 129 | BOOL skipNextTime = ([[alert suppressionButton] state] == NSOnState); 130 | [[NSUserDefaults standardUserDefaults] setBool:skipNextTime forKey:MJSkipDockMenuIconProblemAlertKey]; 131 | } 132 | 133 | - (void) maybeWarnAboutDockMenuProblem { 134 | if (MJMenuIconVisible() || MJDockIconVisible()) 135 | return; 136 | 137 | if ([[NSUserDefaults standardUserDefaults] boolForKey:MJSkipDockMenuIconProblemAlertKey]) 138 | return; 139 | 140 | NSAlert* alert = [[NSAlert alloc] init]; 141 | [alert setAlertStyle:NSWarningAlertStyle]; 142 | [alert setMessageText:@"How to get back to this window"]; 143 | [alert setInformativeText:@"When both the dock icon and menu icon are disabled, you can get back to this Preferences window by activating Mjolnir from Spotlight or by running `open -a Mjolnir` from Terminal, and then pressing Command + Comma."]; 144 | [alert setShowsSuppressionButton:YES]; 145 | [alert beginSheetModalForWindow:[self window] 146 | modalDelegate:self 147 | didEndSelector:@selector(dockMenuProblemAlertDidEnd:returnCode:contextInfo:) 148 | contextInfo:NULL]; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /Mjolnir/MJSecurityUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | BOOL MJVerifySignedData(NSData* sig, NSData* data); 4 | -------------------------------------------------------------------------------- /Mjolnir/MJSecurityUtils.m: -------------------------------------------------------------------------------- 1 | #import "MJSecurityUtils.h" 2 | #import 3 | #import "variables.h" 4 | 5 | static SecKeyRef MJCreatePublicKey(void) { 6 | CFArrayRef items = NULL; 7 | SecKeyRef security_key = NULL; 8 | 9 | NSData* pubkeyData = [MJPublicKey dataUsingEncoding:NSUTF8StringEncoding]; 10 | if ([pubkeyData length] == 0) goto cleanup; 11 | 12 | SecExternalFormat format = kSecFormatOpenSSL; 13 | SecExternalItemType itemType = kSecItemTypePublicKey; 14 | SecItemImportExportKeyParameters parameters = {}; 15 | 16 | OSStatus status = SecItemImport((__bridge CFDataRef)pubkeyData, NULL, &format, &itemType, 0, ¶meters, NULL, &items); 17 | 18 | if (status != noErr) { printf("invalid status: %d\n", status); goto cleanup; } 19 | if (items == NULL) { printf("items were unexpectedly null\n"); goto cleanup; } 20 | if (format != kSecFormatOpenSSL) { printf("format isn't kSecFormatOpenSSL: %d\n", format); goto cleanup; } 21 | if (itemType != kSecItemTypePublicKey) { printf("item type isn't kSecItemTypePublicKey: %d\n", itemType); goto cleanup; } 22 | if (CFArrayGetCount(items) != 1) { printf("items count isn't 1, it's: %ld\n", CFArrayGetCount(items)); goto cleanup; } 23 | 24 | security_key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items, 0)); 25 | 26 | cleanup: 27 | if (items) CFRelease(items); 28 | return security_key; 29 | } 30 | 31 | static NSData* MJDataFromBase64String(NSData* indata, CFErrorRef* error) { 32 | CFDataRef result = NULL; 33 | 34 | SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, error); 35 | if (!decoder) goto cleanup; 36 | 37 | SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, (__bridge CFTypeRef)indata, error); 38 | if (*error) goto cleanup; 39 | 40 | result = SecTransformExecute(decoder, error); 41 | 42 | cleanup: 43 | 44 | if (decoder) CFRelease(decoder); 45 | return (__bridge_transfer NSData*)result; 46 | } 47 | 48 | BOOL MJVerifySignedData(NSData* sig, NSData* data) { 49 | BOOL verified = NO; 50 | 51 | SecKeyRef security_key = NULL; 52 | 53 | NSData *signature = nil; 54 | NSInputStream *input_stream = nil; 55 | 56 | SecGroupTransformRef group = SecTransformCreateGroupTransform(); 57 | SecTransformRef read_transform = NULL; 58 | SecTransformRef digest_transform = NULL; 59 | SecTransformRef verify_transform = NULL; 60 | CFErrorRef error = NULL; 61 | CFBooleanRef success = NULL; 62 | 63 | security_key = MJCreatePublicKey(); 64 | if (security_key == NULL) { printf("security key was null\n"); goto cleanup; } 65 | 66 | signature = MJDataFromBase64String(sig, &error); 67 | if (signature == nil) { printf("signature was null\n"); goto cleanup; } 68 | 69 | input_stream = [NSInputStream inputStreamWithData:data]; 70 | if (input_stream == nil) { printf("input stream was null\n"); goto cleanup; } 71 | 72 | read_transform = SecTransformCreateReadTransformWithReadStream((__bridge CFReadStreamRef)input_stream); 73 | if (read_transform == NULL) { printf("read transform was null\n"); goto cleanup; } 74 | 75 | digest_transform = SecDigestTransformCreate(kSecDigestSHA1, CC_SHA1_DIGEST_LENGTH, NULL); 76 | if (digest_transform == NULL) { printf("digest transform was null\n"); goto cleanup; } 77 | 78 | verify_transform = SecVerifyTransformCreate(security_key, (__bridge CFDataRef)signature, NULL); 79 | if (verify_transform == NULL) { printf("verify transform was null\n"); goto cleanup; } 80 | 81 | SecTransformConnectTransforms(read_transform, kSecTransformOutputAttributeName, digest_transform, kSecTransformInputAttributeName, group, &error); 82 | if (error) { printf("read transform failed to connect to digest transform:\n"); CFShow(error); goto cleanup; } 83 | 84 | SecTransformConnectTransforms(digest_transform, kSecTransformOutputAttributeName, verify_transform, kSecTransformInputAttributeName, group, &error); 85 | if (error) { printf("digest transform failed to connect to verify transform:\n"); CFShow(error); goto cleanup; } 86 | 87 | success = SecTransformExecute(group, &error); 88 | if (error) { printf("executing transform failed: %ld\n", CFErrorGetCode(error)); CFShow(error); goto cleanup; } 89 | 90 | verified = CFBooleanGetValue(success); 91 | 92 | cleanup: 93 | 94 | if (group) CFRelease(group); 95 | if (security_key) CFRelease(security_key); 96 | if (read_transform) CFRelease(read_transform); 97 | if (digest_transform) CFRelease(digest_transform); 98 | if (verify_transform) CFRelease(verify_transform); 99 | if (success) CFRelease(success); 100 | if (error) CFRelease(error); 101 | 102 | return verified; 103 | } 104 | -------------------------------------------------------------------------------- /Mjolnir/MJUpdate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MJUpdate : NSObject 4 | 5 | @property NSString* newerVersion; 6 | @property NSString* yourVersion; 7 | @property BOOL canAutoInstall; 8 | 9 | + (void) checkForUpdate:(void(^)(MJUpdate* updater, NSError* connError))handler; 10 | - (void) install:(void(^)(NSString* error, NSString* reason))handler; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Mjolnir/MJUpdate.m: -------------------------------------------------------------------------------- 1 | #import "MJUpdate.h" 2 | #import "MJFileUtils.h" 3 | #import "MJSecurityUtils.h" 4 | #import "MJVersionUtils.h" 5 | #import "variables.h" 6 | 7 | @interface MJUpdate () 8 | @property NSString* downloadURL; 9 | @property NSString* signature; 10 | @end 11 | 12 | @implementation MJUpdate 13 | 14 | + (void) checkForUpdate:(void(^)(MJUpdate* updater, NSError* connError))handler { 15 | MJDownloadFile(MJUpdatesURL, ^(NSError *connectionError, NSData *data) { 16 | if (!data) { 17 | handler(nil, connectionError); 18 | return; 19 | } 20 | 21 | NSString* wholeString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 22 | NSArray* lines = [wholeString componentsSeparatedByString:@"\n"]; 23 | NSString* versionString = [lines objectAtIndex:0]; 24 | NSString* tgzURL = [lines objectAtIndex:1]; 25 | NSString* signature = [lines objectAtIndex:2]; 26 | 27 | if (MJVersionFromString(versionString) <= MJVersionFromThisApp()) { 28 | handler(nil, nil); 29 | return; 30 | } 31 | 32 | MJUpdate* updater = [[MJUpdate alloc] init]; 33 | updater.signature = signature; 34 | updater.downloadURL = tgzURL; 35 | updater.newerVersion = versionString; 36 | updater.yourVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; 37 | updater.canAutoInstall = [[NSFileManager defaultManager] isDeletableFileAtPath:[[NSBundle mainBundle] bundlePath]]; 38 | handler(updater, nil); 39 | }); 40 | } 41 | 42 | - (void) install:(void(^)(NSString* error, NSString* reason))handler { 43 | MJDownloadFile(self.downloadURL, ^(NSError *connectionError, NSData *tgzdata) { 44 | if (!tgzdata) { 45 | handler(@"Error downloading Mjolnir.tgz", [connectionError localizedDescription]); 46 | return; 47 | } 48 | 49 | if (!MJVerifySignedData([self.signature dataUsingEncoding:NSUTF8StringEncoding], tgzdata)) { 50 | handler(@"Mjolnir.tgz failed security verification!", @"DSA signature could not be verified."); 51 | return; 52 | } 53 | 54 | NSError *__autoreleasing mkTempDirError; 55 | NSString* tempDirectory = MJCreateEmptyTempDirectory(@"mjolnir-", &mkTempDirError); 56 | if (!tempDirectory) { 57 | handler(@"Error creating temporary directory for Mjolnir.tgz", [mkTempDirError localizedDescription]); 58 | return; 59 | } 60 | 61 | NSError* __autoreleasing untarError; 62 | BOOL untarSuccess = MJUntar(tgzdata, tempDirectory, &untarError); 63 | if (!untarSuccess) { 64 | handler(@"Error extracting Mjolnir.tgz", [untarError localizedDescription]); 65 | return; 66 | } 67 | 68 | NSString* thispath = [[NSBundle mainBundle] bundlePath]; 69 | NSString* newpath = [tempDirectory stringByAppendingPathComponent:@"Mjolnir.app"]; 70 | NSString* pidstring = [NSString stringWithFormat:@"%d", getpid()]; 71 | 72 | NSTask* task = [[NSTask alloc] init]; 73 | [task setLaunchPath:[[NSBundle mainBundle] pathForResource:@"MjolnirRestarter" ofType:@""]]; 74 | [task setArguments:@[pidstring, thispath, newpath]]; 75 | [task launch]; 76 | exit(0); 77 | }); 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Mjolnir/MJUpdateChecker.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | void MJUpdateCheckerSetup(void); 4 | 5 | void MJUpdateCheckerCheckSilently(void); 6 | void MJUpdateCheckerCheckVerbosely(void); 7 | 8 | BOOL MJUpdateCheckerEnabled(void); 9 | void MJUpdateCheckerSetEnabled(BOOL checkingEnabled); 10 | -------------------------------------------------------------------------------- /Mjolnir/MJUpdateChecker.m: -------------------------------------------------------------------------------- 1 | #import "MJUpdateChecker.h" 2 | #import "MJAutoUpdaterWindowController.h" 3 | #import "MJUserNotificationManager.h" 4 | #import "MJUpdate.h" 5 | #import "variables.h" 6 | 7 | static CFRunLoopTimerRef autoupdateTimer; 8 | static MJAutoUpdaterWindowController* updaterWindowController; 9 | static id closedObserver; 10 | 11 | void callback(CFRunLoopTimerRef timer, void *info) { 12 | MJUpdateCheckerCheckSilently(); 13 | } 14 | 15 | static void reflect_defaults(void) { 16 | if (MJUpdateCheckerEnabled()) 17 | CFRunLoopAddTimer(CFRunLoopGetMain(), autoupdateTimer, kCFRunLoopCommonModes); 18 | else 19 | CFRunLoopRemoveTimer(CFRunLoopGetMain(), autoupdateTimer, kCFRunLoopCommonModes); 20 | } 21 | 22 | void MJUpdateCheckerSetup(void) { 23 | CFTimeInterval interval = [[NSUserDefaults standardUserDefaults] doubleForKey:MJCheckForUpdatesIntervalKey]; 24 | autoupdateTimer = CFRunLoopTimerCreate(NULL, 0, interval, 0, 0, &callback, NULL); 25 | reflect_defaults(); 26 | 27 | if (MJUpdateCheckerEnabled()) 28 | CFRunLoopTimerSetNextFireDate(autoupdateTimer, CFAbsoluteTimeGetCurrent()); 29 | } 30 | 31 | static MJAutoUpdaterWindowController* definitelyRealWindowController(void) { 32 | if (!updaterWindowController) { 33 | updaterWindowController = [[MJAutoUpdaterWindowController alloc] init]; 34 | closedObserver = [[NSNotificationCenter defaultCenter] 35 | addObserverForName:NSWindowWillCloseNotification 36 | object:[updaterWindowController window] 37 | queue:[NSOperationQueue mainQueue] 38 | usingBlock:^(NSNotification *note) { 39 | updaterWindowController = nil; 40 | 41 | [[NSNotificationCenter defaultCenter] 42 | removeObserver:closedObserver]; 43 | closedObserver = nil; 44 | }]; 45 | } 46 | 47 | return updaterWindowController; 48 | } 49 | 50 | void MJUpdateCheckerCheckSilently(void) { 51 | if (!MJUpdateCheckerEnabled()) 52 | return; 53 | 54 | [MJUpdate checkForUpdate:^(MJUpdate *update, NSError* connError) { 55 | if (update) { 56 | MJAutoUpdaterWindowController* wc = definitelyRealWindowController(); 57 | wc.update = update; 58 | 59 | [[MJUserNotificationManager sharedManager] sendNotification:@"Mjolnir update available" handler:^{ 60 | [wc showFoundPage]; 61 | }]; 62 | } 63 | }]; 64 | } 65 | 66 | BOOL MJUpdateCheckerEnabled(void) { 67 | return [[NSUserDefaults standardUserDefaults] boolForKey:MJCheckForUpdatesKey]; 68 | } 69 | 70 | void MJUpdateCheckerSetEnabled(BOOL checkingEnabled) { 71 | [[NSUserDefaults standardUserDefaults] setBool:checkingEnabled 72 | forKey:MJCheckForUpdatesKey]; 73 | reflect_defaults(); 74 | } 75 | 76 | void MJUpdateCheckerCheckVerbosely(void) { 77 | MJAutoUpdaterWindowController* wc = definitelyRealWindowController(); 78 | 79 | [wc showCheckingPage]; 80 | 81 | [MJUpdate checkForUpdate:^(MJUpdate *update, NSError* connError) { 82 | if (!updaterWindowController) 83 | return; 84 | 85 | if (update) { 86 | wc.update = update; 87 | [wc showFoundPage]; 88 | } 89 | else if (connError) { 90 | wc.error = [connError localizedDescription]; 91 | [wc showErrorPage]; 92 | } 93 | else { 94 | [wc showUpToDatePage]; 95 | } 96 | }]; 97 | } 98 | -------------------------------------------------------------------------------- /Mjolnir/MJUserNotificationManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MJUserNotificationManager : NSObject 4 | 5 | + (MJUserNotificationManager*) sharedManager; 6 | 7 | - (void) sendNotification:(NSString*)title handler:(dispatch_block_t)handler; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Mjolnir/MJUserNotificationManager.m: -------------------------------------------------------------------------------- 1 | #import "MJUserNotificationManager.h" 2 | 3 | @interface MJUserNotificationManager () 4 | @property NSMutableDictionary* callbacks; 5 | @end 6 | 7 | @implementation MJUserNotificationManager 8 | 9 | + (MJUserNotificationManager*) sharedManager { 10 | static MJUserNotificationManager* sharedManager; 11 | static dispatch_once_t onceToken; 12 | dispatch_once(&onceToken, ^{ 13 | sharedManager = [[MJUserNotificationManager alloc] init]; 14 | sharedManager.callbacks = [NSMutableDictionary dictionary]; 15 | [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:sharedManager]; 16 | }); 17 | return sharedManager; 18 | } 19 | 20 | - (void) sendNotification:(NSString*)title handler:(dispatch_block_t)handler { 21 | NSUserNotification* note = [[NSUserNotification alloc] init]; 22 | note.title = title; 23 | [self.callbacks setObject:[handler copy] forKey:note]; 24 | [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: note]; 25 | } 26 | 27 | - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification { 28 | [[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification: notification]; // is this unnecessary? can't tell, docs suck. 29 | 30 | dispatch_block_t callback = [self.callbacks objectForKey: notification]; 31 | if (callback) 32 | callback(); 33 | 34 | [self.callbacks removeObjectForKey: notification]; 35 | } 36 | 37 | - (BOOL) userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { 38 | return YES; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Mjolnir/MJVersionUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int MJVersionFromThisApp(void); 4 | int MJVersionFromString(NSString* str); 5 | -------------------------------------------------------------------------------- /Mjolnir/MJVersionUtils.m: -------------------------------------------------------------------------------- 1 | #import "MJVersionUtils.h" 2 | 3 | int MJVersionFromThisApp(void) { 4 | static int v; 5 | static dispatch_once_t onceToken; 6 | dispatch_once(&onceToken, ^{ 7 | v = MJVersionFromString([[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]); 8 | }); 9 | return v; 10 | } 11 | 12 | int MJVersionFromString(NSString* str) { 13 | NSScanner* scanner = [NSScanner scannerWithString:str]; 14 | int major; 15 | int minor; 16 | int bugfix = 0; 17 | [scanner scanInt:&major]; 18 | [scanner scanString:@"." intoString:NULL]; 19 | [scanner scanInt:&minor]; 20 | if ([scanner scanString:@"." intoString:NULL]) { 21 | [scanner scanInt:&bugfix]; 22 | } 23 | return major * 10000 + minor * 100 + bugfix; 24 | } 25 | -------------------------------------------------------------------------------- /Mjolnir/Mjolnir-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | Mjolnir 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.2 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0.2 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | ${MACOSX_DEPLOYMENT_TARGET} 29 | NSHumanReadableCopyright 30 | Released under MIT license. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /Mjolnir/Mjolnir-Prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | #define LUA_USE_MACOSX 1 6 | -------------------------------------------------------------------------------- /Mjolnir/MjolnirRestarter/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | static NSString* live_app_path; 4 | static NSString* temp_app_path; 5 | static pid_t parent_pid; 6 | static NSImage* app_icon; 7 | 8 | static void MJShowError(NSString* command, NSString* error) { 9 | NSAlert* alert = [[NSAlert alloc] init]; 10 | [alert setAlertStyle: NSCriticalAlertStyle]; 11 | [alert setIcon:app_icon]; 12 | [alert setMessageText:@"Error installing update"]; 13 | [alert setInformativeText:[NSString stringWithFormat:@"Command that failed: %@\n\nError: %@", command, error]]; 14 | [alert runModal]; 15 | } 16 | 17 | static void MJOpenLiveApp(void) { 18 | [[NSWorkspace sharedWorkspace] launchApplication:live_app_path]; 19 | exit(0); 20 | } 21 | 22 | static void MJRelaunch(void) { 23 | NSError* __autoreleasing rmError; 24 | BOOL rmSuccess = [[NSFileManager defaultManager] removeItemAtPath:live_app_path error:&rmError]; 25 | if (!rmSuccess) { 26 | MJShowError([NSString stringWithFormat:@"rm %@", live_app_path], [rmError localizedDescription]); 27 | MJOpenLiveApp(); 28 | } 29 | 30 | NSError* __autoreleasing cpError; 31 | if (![[NSFileManager defaultManager] copyItemAtPath:temp_app_path toPath:live_app_path error:&cpError]) { 32 | MJShowError([NSString stringWithFormat:@"cp %@ %@", temp_app_path, live_app_path], [cpError localizedDescription]); 33 | exit(1); 34 | } 35 | 36 | MJOpenLiveApp(); 37 | } 38 | 39 | static void MJBorrowAppIcon() { 40 | NSString* iconPath = [[NSBundle bundleWithPath:live_app_path] pathForResource:@"Mjolnir" ofType:@"icns"]; 41 | app_icon = [[NSImage alloc] initWithContentsOfFile:iconPath]; 42 | } 43 | 44 | int main(int argc, const char * argv[]) { 45 | @autoreleasepool { 46 | parent_pid = atoi(argv[1]); 47 | live_app_path = [NSString stringWithUTF8String:argv[2]]; 48 | temp_app_path = [NSString stringWithUTF8String:argv[3]]; 49 | 50 | [[[NSWorkspace sharedWorkspace] notificationCenter] 51 | addObserverForName:NSWorkspaceDidTerminateApplicationNotification 52 | object:nil 53 | queue:[NSOperationQueue mainQueue] 54 | usingBlock:^(NSNotification *note) { 55 | NSRunningApplication* app = [[note userInfo] valueForKey:NSWorkspaceApplicationKey]; 56 | if ([app processIdentifier] == parent_pid) { 57 | MJRelaunch(); 58 | } 59 | }]; 60 | 61 | dispatch_async(dispatch_get_main_queue(), ^{ 62 | if (getppid() == 1) { 63 | MJRelaunch(); 64 | } 65 | }); 66 | 67 | MJBorrowAppIcon(); 68 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 69 | [[NSApplication sharedApplication] run]; 70 | } 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /Mjolnir/lua/lapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Auxiliary functions from Lua API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lapi_h 8 | #define lapi_h 9 | 10 | 11 | #include "llimits.h" 12 | #include "lstate.h" 13 | 14 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ 15 | "stack overflow");} 16 | 17 | #define adjustresults(L,nres) \ 18 | { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } 19 | 20 | #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ 21 | "not enough elements in the stack") 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Mjolnir/lua/lbitlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Standard library for bitwise operations 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lbitlib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lua.h" 14 | 15 | #include "lauxlib.h" 16 | #include "lualib.h" 17 | 18 | 19 | #if defined(LUA_COMPAT_BITLIB) /* { */ 20 | 21 | 22 | #define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) 23 | #define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) 24 | 25 | 26 | /* number of bits to consider in a number */ 27 | #if !defined(LUA_NBITS) 28 | #define LUA_NBITS 32 29 | #endif 30 | 31 | 32 | /* 33 | ** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must 34 | ** be made in two parts to avoid problems when LUA_NBITS is equal to the 35 | ** number of bits in a lua_Unsigned.) 36 | */ 37 | #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) 38 | 39 | 40 | /* macro to trim extra bits */ 41 | #define trim(x) ((x) & ALLONES) 42 | 43 | 44 | /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ 45 | #define mask(n) (~((ALLONES << 1) << ((n) - 1))) 46 | 47 | 48 | 49 | static lua_Unsigned andaux (lua_State *L) { 50 | int i, n = lua_gettop(L); 51 | lua_Unsigned r = ~(lua_Unsigned)0; 52 | for (i = 1; i <= n; i++) 53 | r &= checkunsigned(L, i); 54 | return trim(r); 55 | } 56 | 57 | 58 | static int b_and (lua_State *L) { 59 | lua_Unsigned r = andaux(L); 60 | pushunsigned(L, r); 61 | return 1; 62 | } 63 | 64 | 65 | static int b_test (lua_State *L) { 66 | lua_Unsigned r = andaux(L); 67 | lua_pushboolean(L, r != 0); 68 | return 1; 69 | } 70 | 71 | 72 | static int b_or (lua_State *L) { 73 | int i, n = lua_gettop(L); 74 | lua_Unsigned r = 0; 75 | for (i = 1; i <= n; i++) 76 | r |= checkunsigned(L, i); 77 | pushunsigned(L, trim(r)); 78 | return 1; 79 | } 80 | 81 | 82 | static int b_xor (lua_State *L) { 83 | int i, n = lua_gettop(L); 84 | lua_Unsigned r = 0; 85 | for (i = 1; i <= n; i++) 86 | r ^= checkunsigned(L, i); 87 | pushunsigned(L, trim(r)); 88 | return 1; 89 | } 90 | 91 | 92 | static int b_not (lua_State *L) { 93 | lua_Unsigned r = ~checkunsigned(L, 1); 94 | pushunsigned(L, trim(r)); 95 | return 1; 96 | } 97 | 98 | 99 | static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { 100 | if (i < 0) { /* shift right? */ 101 | i = -i; 102 | r = trim(r); 103 | if (i >= LUA_NBITS) r = 0; 104 | else r >>= i; 105 | } 106 | else { /* shift left */ 107 | if (i >= LUA_NBITS) r = 0; 108 | else r <<= i; 109 | r = trim(r); 110 | } 111 | pushunsigned(L, r); 112 | return 1; 113 | } 114 | 115 | 116 | static int b_lshift (lua_State *L) { 117 | return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); 118 | } 119 | 120 | 121 | static int b_rshift (lua_State *L) { 122 | return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); 123 | } 124 | 125 | 126 | static int b_arshift (lua_State *L) { 127 | lua_Unsigned r = checkunsigned(L, 1); 128 | lua_Integer i = luaL_checkinteger(L, 2); 129 | if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) 130 | return b_shift(L, r, -i); 131 | else { /* arithmetic shift for 'negative' number */ 132 | if (i >= LUA_NBITS) r = ALLONES; 133 | else 134 | r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ 135 | pushunsigned(L, r); 136 | return 1; 137 | } 138 | } 139 | 140 | 141 | static int b_rot (lua_State *L, lua_Integer d) { 142 | lua_Unsigned r = checkunsigned(L, 1); 143 | int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ 144 | r = trim(r); 145 | if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ 146 | r = (r << i) | (r >> (LUA_NBITS - i)); 147 | pushunsigned(L, trim(r)); 148 | return 1; 149 | } 150 | 151 | 152 | static int b_lrot (lua_State *L) { 153 | return b_rot(L, luaL_checkinteger(L, 2)); 154 | } 155 | 156 | 157 | static int b_rrot (lua_State *L) { 158 | return b_rot(L, -luaL_checkinteger(L, 2)); 159 | } 160 | 161 | 162 | /* 163 | ** get field and width arguments for field-manipulation functions, 164 | ** checking whether they are valid. 165 | ** ('luaL_error' called without 'return' to avoid later warnings about 166 | ** 'width' being used uninitialized.) 167 | */ 168 | static int fieldargs (lua_State *L, int farg, int *width) { 169 | lua_Integer f = luaL_checkinteger(L, farg); 170 | lua_Integer w = luaL_optinteger(L, farg + 1, 1); 171 | luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); 172 | luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); 173 | if (f + w > LUA_NBITS) 174 | luaL_error(L, "trying to access non-existent bits"); 175 | *width = (int)w; 176 | return (int)f; 177 | } 178 | 179 | 180 | static int b_extract (lua_State *L) { 181 | int w; 182 | lua_Unsigned r = trim(checkunsigned(L, 1)); 183 | int f = fieldargs(L, 2, &w); 184 | r = (r >> f) & mask(w); 185 | pushunsigned(L, r); 186 | return 1; 187 | } 188 | 189 | 190 | static int b_replace (lua_State *L) { 191 | int w; 192 | lua_Unsigned r = trim(checkunsigned(L, 1)); 193 | lua_Unsigned v = trim(checkunsigned(L, 2)); 194 | int f = fieldargs(L, 3, &w); 195 | lua_Unsigned m = mask(w); 196 | r = (r & ~(m << f)) | ((v & m) << f); 197 | pushunsigned(L, r); 198 | return 1; 199 | } 200 | 201 | 202 | static const luaL_Reg bitlib[] = { 203 | {"arshift", b_arshift}, 204 | {"band", b_and}, 205 | {"bnot", b_not}, 206 | {"bor", b_or}, 207 | {"bxor", b_xor}, 208 | {"btest", b_test}, 209 | {"extract", b_extract}, 210 | {"lrotate", b_lrot}, 211 | {"lshift", b_lshift}, 212 | {"replace", b_replace}, 213 | {"rrotate", b_rrot}, 214 | {"rshift", b_rshift}, 215 | {NULL, NULL} 216 | }; 217 | 218 | 219 | 220 | LUAMOD_API int luaopen_bit32 (lua_State *L) { 221 | luaL_newlib(L, bitlib); 222 | return 1; 223 | } 224 | 225 | 226 | #else /* }{ */ 227 | 228 | 229 | LUAMOD_API int luaopen_bit32 (lua_State *L) { 230 | return luaL_error(L, "library 'bit32' has been deprecated"); 231 | } 232 | 233 | #endif /* } */ 234 | -------------------------------------------------------------------------------- /Mjolnir/lua/lcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Code generator for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lcode_h 8 | #define lcode_h 9 | 10 | #include "llex.h" 11 | #include "lobject.h" 12 | #include "lopcodes.h" 13 | #include "lparser.h" 14 | 15 | 16 | /* 17 | ** Marks the end of a patch list. It is an invalid value both as an absolute 18 | ** address, and as a list link (would link an element to itself). 19 | */ 20 | #define NO_JUMP (-1) 21 | 22 | 23 | /* 24 | ** grep "ORDER OPR" if you change these enums (ORDER OP) 25 | */ 26 | typedef enum BinOpr { 27 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, 28 | OPR_DIV, 29 | OPR_IDIV, 30 | OPR_BAND, OPR_BOR, OPR_BXOR, 31 | OPR_SHL, OPR_SHR, 32 | OPR_CONCAT, 33 | OPR_EQ, OPR_LT, OPR_LE, 34 | OPR_NE, OPR_GT, OPR_GE, 35 | OPR_AND, OPR_OR, 36 | OPR_NOBINOPR 37 | } BinOpr; 38 | 39 | 40 | typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; 41 | 42 | 43 | /* get (pointer to) instruction of given 'expdesc' */ 44 | #define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) 45 | 46 | #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) 47 | 48 | #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) 49 | 50 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 51 | 52 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 53 | LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); 54 | LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); 55 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 56 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 57 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 58 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 59 | LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); 60 | LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); 61 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); 62 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); 63 | LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); 64 | LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); 65 | LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); 66 | LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); 67 | LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); 68 | LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); 69 | LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); 70 | LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); 71 | LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); 72 | LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); 73 | LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); 74 | LUAI_FUNC int luaK_jump (FuncState *fs); 75 | LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); 76 | LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); 77 | LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); 78 | LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); 79 | LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); 80 | LUAI_FUNC int luaK_getlabel (FuncState *fs); 81 | LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); 82 | LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); 83 | LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, 84 | expdesc *v2, int line); 85 | LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); 86 | 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /Mjolnir/lua/lcorolib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Coroutine Library 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lcorolib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lauxlib.h" 18 | #include "lualib.h" 19 | 20 | 21 | static lua_State *getco (lua_State *L) { 22 | lua_State *co = lua_tothread(L, 1); 23 | luaL_argcheck(L, co, 1, "thread expected"); 24 | return co; 25 | } 26 | 27 | 28 | static int auxresume (lua_State *L, lua_State *co, int narg) { 29 | int status; 30 | if (!lua_checkstack(co, narg)) { 31 | lua_pushliteral(L, "too many arguments to resume"); 32 | return -1; /* error flag */ 33 | } 34 | if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { 35 | lua_pushliteral(L, "cannot resume dead coroutine"); 36 | return -1; /* error flag */ 37 | } 38 | lua_xmove(L, co, narg); 39 | status = lua_resume(co, L, narg); 40 | if (status == LUA_OK || status == LUA_YIELD) { 41 | int nres = lua_gettop(co); 42 | if (!lua_checkstack(L, nres + 1)) { 43 | lua_pop(co, nres); /* remove results anyway */ 44 | lua_pushliteral(L, "too many results to resume"); 45 | return -1; /* error flag */ 46 | } 47 | lua_xmove(co, L, nres); /* move yielded values */ 48 | return nres; 49 | } 50 | else { 51 | lua_xmove(co, L, 1); /* move error message */ 52 | return -1; /* error flag */ 53 | } 54 | } 55 | 56 | 57 | static int luaB_coresume (lua_State *L) { 58 | lua_State *co = getco(L); 59 | int r; 60 | r = auxresume(L, co, lua_gettop(L) - 1); 61 | if (r < 0) { 62 | lua_pushboolean(L, 0); 63 | lua_insert(L, -2); 64 | return 2; /* return false + error message */ 65 | } 66 | else { 67 | lua_pushboolean(L, 1); 68 | lua_insert(L, -(r + 1)); 69 | return r + 1; /* return true + 'resume' returns */ 70 | } 71 | } 72 | 73 | 74 | static int luaB_auxwrap (lua_State *L) { 75 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); 76 | int r = auxresume(L, co, lua_gettop(L)); 77 | if (r < 0) { 78 | if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ 79 | luaL_where(L, 1); /* add extra info */ 80 | lua_insert(L, -2); 81 | lua_concat(L, 2); 82 | } 83 | return lua_error(L); /* propagate error */ 84 | } 85 | return r; 86 | } 87 | 88 | 89 | static int luaB_cocreate (lua_State *L) { 90 | lua_State *NL; 91 | luaL_checktype(L, 1, LUA_TFUNCTION); 92 | NL = lua_newthread(L); 93 | lua_pushvalue(L, 1); /* move function to top */ 94 | lua_xmove(L, NL, 1); /* move function from L to NL */ 95 | return 1; 96 | } 97 | 98 | 99 | static int luaB_cowrap (lua_State *L) { 100 | luaB_cocreate(L); 101 | lua_pushcclosure(L, luaB_auxwrap, 1); 102 | return 1; 103 | } 104 | 105 | 106 | static int luaB_yield (lua_State *L) { 107 | return lua_yield(L, lua_gettop(L)); 108 | } 109 | 110 | 111 | static int luaB_costatus (lua_State *L) { 112 | lua_State *co = getco(L); 113 | if (L == co) lua_pushliteral(L, "running"); 114 | else { 115 | switch (lua_status(co)) { 116 | case LUA_YIELD: 117 | lua_pushliteral(L, "suspended"); 118 | break; 119 | case LUA_OK: { 120 | lua_Debug ar; 121 | if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ 122 | lua_pushliteral(L, "normal"); /* it is running */ 123 | else if (lua_gettop(co) == 0) 124 | lua_pushliteral(L, "dead"); 125 | else 126 | lua_pushliteral(L, "suspended"); /* initial state */ 127 | break; 128 | } 129 | default: /* some error occurred */ 130 | lua_pushliteral(L, "dead"); 131 | break; 132 | } 133 | } 134 | return 1; 135 | } 136 | 137 | 138 | static int luaB_yieldable (lua_State *L) { 139 | lua_pushboolean(L, lua_isyieldable(L)); 140 | return 1; 141 | } 142 | 143 | 144 | static int luaB_corunning (lua_State *L) { 145 | int ismain = lua_pushthread(L); 146 | lua_pushboolean(L, ismain); 147 | return 2; 148 | } 149 | 150 | 151 | static const luaL_Reg co_funcs[] = { 152 | {"create", luaB_cocreate}, 153 | {"resume", luaB_coresume}, 154 | {"running", luaB_corunning}, 155 | {"status", luaB_costatus}, 156 | {"wrap", luaB_cowrap}, 157 | {"yield", luaB_yield}, 158 | {"isyieldable", luaB_yieldable}, 159 | {NULL, NULL} 160 | }; 161 | 162 | 163 | 164 | LUAMOD_API int luaopen_coroutine (lua_State *L) { 165 | luaL_newlib(L, co_funcs); 166 | return 1; 167 | } 168 | 169 | -------------------------------------------------------------------------------- /Mjolnir/lua/lctype.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lctype_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lctype.h" 14 | 15 | #if !LUA_USE_CTYPE /* { */ 16 | 17 | #include 18 | 19 | LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 20 | 0x00, /* EOZ */ 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 22 | 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 26 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 27 | 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 28 | 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 29 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 30 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 31 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 32 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 33 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 34 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 35 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 36 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | }; 54 | 55 | #endif /* } */ 56 | -------------------------------------------------------------------------------- /Mjolnir/lua/lctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lctype_h 8 | #define lctype_h 9 | 10 | #include "lua.h" 11 | 12 | 13 | /* 14 | ** WARNING: the functions defined here do not necessarily correspond 15 | ** to the similar functions in the standard C ctype.h. They are 16 | ** optimized for the specific needs of Lua 17 | */ 18 | 19 | #if !defined(LUA_USE_CTYPE) 20 | 21 | #if 'A' == 65 && '0' == 48 22 | /* ASCII case: can use its own tables; faster and fixed */ 23 | #define LUA_USE_CTYPE 0 24 | #else 25 | /* must use standard C ctype */ 26 | #define LUA_USE_CTYPE 1 27 | #endif 28 | 29 | #endif 30 | 31 | 32 | #if !LUA_USE_CTYPE /* { */ 33 | 34 | #include 35 | 36 | #include "llimits.h" 37 | 38 | 39 | #define ALPHABIT 0 40 | #define DIGITBIT 1 41 | #define PRINTBIT 2 42 | #define SPACEBIT 3 43 | #define XDIGITBIT 4 44 | 45 | 46 | #define MASK(B) (1 << (B)) 47 | 48 | 49 | /* 50 | ** add 1 to char to allow index -1 (EOZ) 51 | */ 52 | #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) 53 | 54 | /* 55 | ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' 56 | */ 57 | #define lislalpha(c) testprop(c, MASK(ALPHABIT)) 58 | #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) 59 | #define lisdigit(c) testprop(c, MASK(DIGITBIT)) 60 | #define lisspace(c) testprop(c, MASK(SPACEBIT)) 61 | #define lisprint(c) testprop(c, MASK(PRINTBIT)) 62 | #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) 63 | 64 | /* 65 | ** this 'ltolower' only works for alphabetic characters 66 | */ 67 | #define ltolower(c) ((c) | ('A' ^ 'a')) 68 | 69 | 70 | /* two more entries for 0 and -1 (EOZ) */ 71 | LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; 72 | 73 | 74 | #else /* }{ */ 75 | 76 | /* 77 | ** use standard C ctypes 78 | */ 79 | 80 | #include 81 | 82 | 83 | #define lislalpha(c) (isalpha(c) || (c) == '_') 84 | #define lislalnum(c) (isalnum(c) || (c) == '_') 85 | #define lisdigit(c) (isdigit(c)) 86 | #define lisspace(c) (isspace(c)) 87 | #define lisprint(c) (isprint(c)) 88 | #define lisxdigit(c) (isxdigit(c)) 89 | 90 | #define ltolower(c) (tolower(c)) 91 | 92 | #endif /* } */ 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /Mjolnir/lua/ldebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Auxiliary functions from Debug Interface module 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldebug_h 8 | #define ldebug_h 9 | 10 | 11 | #include "lstate.h" 12 | 13 | 14 | #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) 15 | 16 | #define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) 17 | 18 | #define resethookcount(L) (L->hookcount = L->basehookcount) 19 | 20 | 21 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, 22 | const char *opname); 23 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, 24 | const TValue *p2); 25 | LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, 26 | const TValue *p2, 27 | const char *msg); 28 | LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, 29 | const TValue *p2); 30 | LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, 31 | const TValue *p2); 32 | LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); 33 | LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, 34 | TString *src, int line); 35 | LUAI_FUNC l_noret luaG_errormsg (lua_State *L); 36 | LUAI_FUNC void luaG_traceexec (lua_State *L); 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Mjolnir/lua/ldo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Stack and Call structure of Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldo_h 8 | #define ldo_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | #include "lzio.h" 14 | 15 | 16 | /* 17 | ** Macro to check stack size and grow stack if needed. Parameters 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the 19 | ** stack across reallocations, doing the work only when needed. 20 | ** 'condmovestack' is used in heavy tests to force a stack reallocation 21 | ** at every check. 22 | */ 23 | #define luaD_checkstackaux(L,n,pre,pos) \ 24 | if (L->stack_last - L->top <= (n)) \ 25 | { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } 26 | 27 | /* In general, 'pre'/'pos' are empty (nothing to save) */ 28 | #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) 29 | 30 | 31 | 32 | #define savestack(L,p) ((char *)(p) - (char *)L->stack) 33 | #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) 34 | 35 | 36 | /* type of protected functions, to be ran by 'runprotected' */ 37 | typedef void (*Pfunc) (lua_State *L, void *ud); 38 | 39 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, 40 | const char *mode); 41 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); 42 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); 43 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 44 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 45 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, 46 | ptrdiff_t oldtop, ptrdiff_t ef); 47 | LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, 48 | int nres); 49 | LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); 50 | LUAI_FUNC void luaD_growstack (lua_State *L, int n); 51 | LUAI_FUNC void luaD_shrinkstack (lua_State *L); 52 | LUAI_FUNC void luaD_inctop (lua_State *L); 53 | 54 | LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); 55 | LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /Mjolnir/lua/ldump.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** save precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ldump_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lobject.h" 18 | #include "lstate.h" 19 | #include "lundump.h" 20 | 21 | 22 | typedef struct { 23 | lua_State *L; 24 | lua_Writer writer; 25 | void *data; 26 | int strip; 27 | int status; 28 | } DumpState; 29 | 30 | 31 | /* 32 | ** All high-level dumps go through DumpVector; you can change it to 33 | ** change the endianness of the result 34 | */ 35 | #define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) 36 | 37 | #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) 38 | 39 | 40 | static void DumpBlock (const void *b, size_t size, DumpState *D) { 41 | if (D->status == 0 && size > 0) { 42 | lua_unlock(D->L); 43 | D->status = (*D->writer)(D->L, b, size, D->data); 44 | lua_lock(D->L); 45 | } 46 | } 47 | 48 | 49 | #define DumpVar(x,D) DumpVector(&x,1,D) 50 | 51 | 52 | static void DumpByte (int y, DumpState *D) { 53 | lu_byte x = (lu_byte)y; 54 | DumpVar(x, D); 55 | } 56 | 57 | 58 | static void DumpInt (int x, DumpState *D) { 59 | DumpVar(x, D); 60 | } 61 | 62 | 63 | static void DumpNumber (lua_Number x, DumpState *D) { 64 | DumpVar(x, D); 65 | } 66 | 67 | 68 | static void DumpInteger (lua_Integer x, DumpState *D) { 69 | DumpVar(x, D); 70 | } 71 | 72 | 73 | static void DumpString (const TString *s, DumpState *D) { 74 | if (s == NULL) 75 | DumpByte(0, D); 76 | else { 77 | size_t size = tsslen(s) + 1; /* include trailing '\0' */ 78 | const char *str = getstr(s); 79 | if (size < 0xFF) 80 | DumpByte(cast_int(size), D); 81 | else { 82 | DumpByte(0xFF, D); 83 | DumpVar(size, D); 84 | } 85 | DumpVector(str, size - 1, D); /* no need to save '\0' */ 86 | } 87 | } 88 | 89 | 90 | static void DumpCode (const Proto *f, DumpState *D) { 91 | DumpInt(f->sizecode, D); 92 | DumpVector(f->code, f->sizecode, D); 93 | } 94 | 95 | 96 | static void DumpFunction(const Proto *f, TString *psource, DumpState *D); 97 | 98 | static void DumpConstants (const Proto *f, DumpState *D) { 99 | int i; 100 | int n = f->sizek; 101 | DumpInt(n, D); 102 | for (i = 0; i < n; i++) { 103 | const TValue *o = &f->k[i]; 104 | DumpByte(ttype(o), D); 105 | switch (ttype(o)) { 106 | case LUA_TNIL: 107 | break; 108 | case LUA_TBOOLEAN: 109 | DumpByte(bvalue(o), D); 110 | break; 111 | case LUA_TNUMFLT: 112 | DumpNumber(fltvalue(o), D); 113 | break; 114 | case LUA_TNUMINT: 115 | DumpInteger(ivalue(o), D); 116 | break; 117 | case LUA_TSHRSTR: 118 | case LUA_TLNGSTR: 119 | DumpString(tsvalue(o), D); 120 | break; 121 | default: 122 | lua_assert(0); 123 | } 124 | } 125 | } 126 | 127 | 128 | static void DumpProtos (const Proto *f, DumpState *D) { 129 | int i; 130 | int n = f->sizep; 131 | DumpInt(n, D); 132 | for (i = 0; i < n; i++) 133 | DumpFunction(f->p[i], f->source, D); 134 | } 135 | 136 | 137 | static void DumpUpvalues (const Proto *f, DumpState *D) { 138 | int i, n = f->sizeupvalues; 139 | DumpInt(n, D); 140 | for (i = 0; i < n; i++) { 141 | DumpByte(f->upvalues[i].instack, D); 142 | DumpByte(f->upvalues[i].idx, D); 143 | } 144 | } 145 | 146 | 147 | static void DumpDebug (const Proto *f, DumpState *D) { 148 | int i, n; 149 | n = (D->strip) ? 0 : f->sizelineinfo; 150 | DumpInt(n, D); 151 | DumpVector(f->lineinfo, n, D); 152 | n = (D->strip) ? 0 : f->sizelocvars; 153 | DumpInt(n, D); 154 | for (i = 0; i < n; i++) { 155 | DumpString(f->locvars[i].varname, D); 156 | DumpInt(f->locvars[i].startpc, D); 157 | DumpInt(f->locvars[i].endpc, D); 158 | } 159 | n = (D->strip) ? 0 : f->sizeupvalues; 160 | DumpInt(n, D); 161 | for (i = 0; i < n; i++) 162 | DumpString(f->upvalues[i].name, D); 163 | } 164 | 165 | 166 | static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { 167 | if (D->strip || f->source == psource) 168 | DumpString(NULL, D); /* no debug info or same source as its parent */ 169 | else 170 | DumpString(f->source, D); 171 | DumpInt(f->linedefined, D); 172 | DumpInt(f->lastlinedefined, D); 173 | DumpByte(f->numparams, D); 174 | DumpByte(f->is_vararg, D); 175 | DumpByte(f->maxstacksize, D); 176 | DumpCode(f, D); 177 | DumpConstants(f, D); 178 | DumpUpvalues(f, D); 179 | DumpProtos(f, D); 180 | DumpDebug(f, D); 181 | } 182 | 183 | 184 | static void DumpHeader (DumpState *D) { 185 | DumpLiteral(LUA_SIGNATURE, D); 186 | DumpByte(LUAC_VERSION, D); 187 | DumpByte(LUAC_FORMAT, D); 188 | DumpLiteral(LUAC_DATA, D); 189 | DumpByte(sizeof(int), D); 190 | DumpByte(sizeof(size_t), D); 191 | DumpByte(sizeof(Instruction), D); 192 | DumpByte(sizeof(lua_Integer), D); 193 | DumpByte(sizeof(lua_Number), D); 194 | DumpInteger(LUAC_INT, D); 195 | DumpNumber(LUAC_NUM, D); 196 | } 197 | 198 | 199 | /* 200 | ** dump Lua function as precompiled chunk 201 | */ 202 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, 203 | int strip) { 204 | DumpState D; 205 | D.L = L; 206 | D.writer = w; 207 | D.data = data; 208 | D.strip = strip; 209 | D.status = 0; 210 | DumpHeader(&D); 211 | DumpByte(f->sizeupvalues, &D); 212 | DumpFunction(f, NULL, &D); 213 | return D.status; 214 | } 215 | 216 | -------------------------------------------------------------------------------- /Mjolnir/lua/lfunc.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lfunc_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lfunc.h" 18 | #include "lgc.h" 19 | #include "lmem.h" 20 | #include "lobject.h" 21 | #include "lstate.h" 22 | 23 | 24 | 25 | CClosure *luaF_newCclosure (lua_State *L, int n) { 26 | GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); 27 | CClosure *c = gco2ccl(o); 28 | c->nupvalues = cast_byte(n); 29 | return c; 30 | } 31 | 32 | 33 | LClosure *luaF_newLclosure (lua_State *L, int n) { 34 | GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); 35 | LClosure *c = gco2lcl(o); 36 | c->p = NULL; 37 | c->nupvalues = cast_byte(n); 38 | while (n--) c->upvals[n] = NULL; 39 | return c; 40 | } 41 | 42 | /* 43 | ** fill a closure with new closed upvalues 44 | */ 45 | void luaF_initupvals (lua_State *L, LClosure *cl) { 46 | int i; 47 | for (i = 0; i < cl->nupvalues; i++) { 48 | UpVal *uv = luaM_new(L, UpVal); 49 | uv->refcount = 1; 50 | uv->v = &uv->u.value; /* make it closed */ 51 | setnilvalue(uv->v); 52 | cl->upvals[i] = uv; 53 | } 54 | } 55 | 56 | 57 | UpVal *luaF_findupval (lua_State *L, StkId level) { 58 | UpVal **pp = &L->openupval; 59 | UpVal *p; 60 | UpVal *uv; 61 | lua_assert(isintwups(L) || L->openupval == NULL); 62 | while (*pp != NULL && (p = *pp)->v >= level) { 63 | lua_assert(upisopen(p)); 64 | if (p->v == level) /* found a corresponding upvalue? */ 65 | return p; /* return it */ 66 | pp = &p->u.open.next; 67 | } 68 | /* not found: create a new upvalue */ 69 | uv = luaM_new(L, UpVal); 70 | uv->refcount = 0; 71 | uv->u.open.next = *pp; /* link it to list of open upvalues */ 72 | uv->u.open.touched = 1; 73 | *pp = uv; 74 | uv->v = level; /* current value lives in the stack */ 75 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ 76 | L->twups = G(L)->twups; /* link it to the list */ 77 | G(L)->twups = L; 78 | } 79 | return uv; 80 | } 81 | 82 | 83 | void luaF_close (lua_State *L, StkId level) { 84 | UpVal *uv; 85 | while (L->openupval != NULL && (uv = L->openupval)->v >= level) { 86 | lua_assert(upisopen(uv)); 87 | L->openupval = uv->u.open.next; /* remove from 'open' list */ 88 | if (uv->refcount == 0) /* no references? */ 89 | luaM_free(L, uv); /* free upvalue */ 90 | else { 91 | setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ 92 | uv->v = &uv->u.value; /* now current value lives here */ 93 | luaC_upvalbarrier(L, uv); 94 | } 95 | } 96 | } 97 | 98 | 99 | Proto *luaF_newproto (lua_State *L) { 100 | GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); 101 | Proto *f = gco2p(o); 102 | f->k = NULL; 103 | f->sizek = 0; 104 | f->p = NULL; 105 | f->sizep = 0; 106 | f->code = NULL; 107 | f->cache = NULL; 108 | f->sizecode = 0; 109 | f->lineinfo = NULL; 110 | f->sizelineinfo = 0; 111 | f->upvalues = NULL; 112 | f->sizeupvalues = 0; 113 | f->numparams = 0; 114 | f->is_vararg = 0; 115 | f->maxstacksize = 0; 116 | f->locvars = NULL; 117 | f->sizelocvars = 0; 118 | f->linedefined = 0; 119 | f->lastlinedefined = 0; 120 | f->source = NULL; 121 | return f; 122 | } 123 | 124 | 125 | void luaF_freeproto (lua_State *L, Proto *f) { 126 | luaM_freearray(L, f->code, f->sizecode); 127 | luaM_freearray(L, f->p, f->sizep); 128 | luaM_freearray(L, f->k, f->sizek); 129 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); 130 | luaM_freearray(L, f->locvars, f->sizelocvars); 131 | luaM_freearray(L, f->upvalues, f->sizeupvalues); 132 | luaM_free(L, f); 133 | } 134 | 135 | 136 | /* 137 | ** Look for n-th local variable at line 'line' in function 'func'. 138 | ** Returns NULL if not found. 139 | */ 140 | const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { 141 | int i; 142 | for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { 143 | if (pc < f->locvars[i].endpc) { /* is variable active? */ 144 | local_number--; 145 | if (local_number == 0) 146 | return getstr(f->locvars[i].varname); 147 | } 148 | } 149 | return NULL; /* not found */ 150 | } 151 | 152 | -------------------------------------------------------------------------------- /Mjolnir/lua/lfunc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lfunc_h 8 | #define lfunc_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ 15 | cast(int, sizeof(TValue)*((n)-1))) 16 | 17 | #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ 18 | cast(int, sizeof(TValue *)*((n)-1))) 19 | 20 | 21 | /* test whether thread is in 'twups' list */ 22 | #define isintwups(L) (L->twups != L) 23 | 24 | 25 | /* 26 | ** maximum number of upvalues in a closure (both C and Lua). (Value 27 | ** must fit in a VM register.) 28 | */ 29 | #define MAXUPVAL 255 30 | 31 | 32 | /* 33 | ** Upvalues for Lua closures 34 | */ 35 | struct UpVal { 36 | TValue *v; /* points to stack or to its own value */ 37 | lu_mem refcount; /* reference counter */ 38 | union { 39 | struct { /* (when open) */ 40 | UpVal *next; /* linked list */ 41 | int touched; /* mark to avoid cycles with dead threads */ 42 | } open; 43 | TValue value; /* the value (when closed) */ 44 | } u; 45 | }; 46 | 47 | #define upisopen(up) ((up)->v != &(up)->u.value) 48 | 49 | 50 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); 51 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); 52 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); 53 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 55 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); 56 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 57 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 58 | int pc); 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Mjolnir/lua/lgc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $ 3 | ** Garbage Collector 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lgc_h 8 | #define lgc_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | /* 15 | ** Collectable objects may have one of three colors: white, which 16 | ** means the object is not marked; gray, which means the 17 | ** object is marked, but its references may be not marked; and 18 | ** black, which means that the object and all its references are marked. 19 | ** The main invariant of the garbage collector, while marking objects, 20 | ** is that a black object can never point to a white one. Moreover, 21 | ** any gray object must be in a "gray list" (gray, grayagain, weak, 22 | ** allweak, ephemeron) so that it can be visited again before finishing 23 | ** the collection cycle. These lists have no meaning when the invariant 24 | ** is not being enforced (e.g., sweep phase). 25 | */ 26 | 27 | 28 | 29 | /* how much to allocate before next GC step */ 30 | #if !defined(GCSTEPSIZE) 31 | /* ~100 small strings */ 32 | #define GCSTEPSIZE (cast_int(100 * sizeof(TString))) 33 | #endif 34 | 35 | 36 | /* 37 | ** Possible states of the Garbage Collector 38 | */ 39 | #define GCSpropagate 0 40 | #define GCSatomic 1 41 | #define GCSswpallgc 2 42 | #define GCSswpfinobj 3 43 | #define GCSswptobefnz 4 44 | #define GCSswpend 5 45 | #define GCScallfin 6 46 | #define GCSpause 7 47 | 48 | 49 | #define issweepphase(g) \ 50 | (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) 51 | 52 | 53 | /* 54 | ** macro to tell when main invariant (white objects cannot point to black 55 | ** ones) must be kept. During a collection, the sweep 56 | ** phase may break the invariant, as objects turned white may point to 57 | ** still-black objects. The invariant is restored when sweep ends and 58 | ** all objects are white again. 59 | */ 60 | 61 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) 62 | 63 | 64 | /* 65 | ** some useful bit tricks 66 | */ 67 | #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) 68 | #define setbits(x,m) ((x) |= (m)) 69 | #define testbits(x,m) ((x) & (m)) 70 | #define bitmask(b) (1<<(b)) 71 | #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) 72 | #define l_setbit(x,b) setbits(x, bitmask(b)) 73 | #define resetbit(x,b) resetbits(x, bitmask(b)) 74 | #define testbit(x,b) testbits(x, bitmask(b)) 75 | 76 | 77 | /* Layout for bit use in 'marked' field: */ 78 | #define WHITE0BIT 0 /* object is white (type 0) */ 79 | #define WHITE1BIT 1 /* object is white (type 1) */ 80 | #define BLACKBIT 2 /* object is black */ 81 | #define FINALIZEDBIT 3 /* object has been marked for finalization */ 82 | /* bit 7 is currently used by tests (luaL_checkmemory) */ 83 | 84 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) 85 | 86 | 87 | #define iswhite(x) testbits((x)->marked, WHITEBITS) 88 | #define isblack(x) testbit((x)->marked, BLACKBIT) 89 | #define isgray(x) /* neither white nor black */ \ 90 | (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) 91 | 92 | #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) 93 | 94 | #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) 95 | #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) 96 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) 97 | 98 | #define changewhite(x) ((x)->marked ^= WHITEBITS) 99 | #define gray2black(x) l_setbit((x)->marked, BLACKBIT) 100 | 101 | #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) 102 | 103 | 104 | /* 105 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' 106 | ** allows some adjustments to be done only when needed. macro 107 | ** 'condchangemem' is used only for heavy tests (forcing a full 108 | ** GC cycle on every opportunity) 109 | */ 110 | #define luaC_condGC(L,pre,pos) \ 111 | { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ 112 | condchangemem(L,pre,pos); } 113 | 114 | /* more often than not, 'pre'/'pos' are empty */ 115 | #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) 116 | 117 | 118 | #define luaC_barrier(L,p,v) ( \ 119 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 120 | luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) 121 | 122 | #define luaC_barrierback(L,p,v) ( \ 123 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 124 | luaC_barrierback_(L,p) : cast_void(0)) 125 | 126 | #define luaC_objbarrier(L,p,o) ( \ 127 | (isblack(p) && iswhite(o)) ? \ 128 | luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) 129 | 130 | #define luaC_upvalbarrier(L,uv) ( \ 131 | (iscollectable((uv)->v) && !upisopen(uv)) ? \ 132 | luaC_upvalbarrier_(L,uv) : cast_void(0)) 133 | 134 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 135 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); 136 | LUAI_FUNC void luaC_step (lua_State *L); 137 | LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); 138 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); 139 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 140 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 141 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); 142 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); 143 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 144 | LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); 145 | 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /Mjolnir/lua/linit.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Initialization of libraries for lua.c and other clients 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #define linit_c 9 | #define LUA_LIB 10 | 11 | /* 12 | ** If you embed Lua in your program and need to open the standard 13 | ** libraries, call luaL_openlibs in your program. If you need a 14 | ** different set of libraries, copy this file to your project and edit 15 | ** it to suit your needs. 16 | ** 17 | ** You can also *preload* libraries, so that a later 'require' can 18 | ** open the library, which is already linked to the application. 19 | ** For that, do the following code: 20 | ** 21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 22 | ** lua_pushcfunction(L, luaopen_modname); 23 | ** lua_setfield(L, -2, modname); 24 | ** lua_pop(L, 1); // remove PRELOAD table 25 | */ 26 | 27 | #include "lprefix.h" 28 | 29 | 30 | #include 31 | 32 | #include "lua.h" 33 | 34 | #include "lualib.h" 35 | #include "lauxlib.h" 36 | 37 | 38 | /* 39 | ** these libs are loaded by lua.c and are readily available to any Lua 40 | ** program 41 | */ 42 | static const luaL_Reg loadedlibs[] = { 43 | {"_G", luaopen_base}, 44 | {LUA_LOADLIBNAME, luaopen_package}, 45 | {LUA_COLIBNAME, luaopen_coroutine}, 46 | {LUA_TABLIBNAME, luaopen_table}, 47 | {LUA_IOLIBNAME, luaopen_io}, 48 | {LUA_OSLIBNAME, luaopen_os}, 49 | {LUA_STRLIBNAME, luaopen_string}, 50 | {LUA_MATHLIBNAME, luaopen_math}, 51 | {LUA_UTF8LIBNAME, luaopen_utf8}, 52 | {LUA_DBLIBNAME, luaopen_debug}, 53 | #if defined(LUA_COMPAT_BITLIB) 54 | {LUA_BITLIBNAME, luaopen_bit32}, 55 | #endif 56 | {NULL, NULL} 57 | }; 58 | 59 | 60 | LUALIB_API void luaL_openlibs (lua_State *L) { 61 | const luaL_Reg *lib; 62 | /* "require" functions from 'loadedlibs' and set results to global table */ 63 | for (lib = loadedlibs; lib->func; lib++) { 64 | luaL_requiref(L, lib->name, lib->func, 1); 65 | lua_pop(L, 1); /* remove lib */ 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Mjolnir/lua/llex.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Lexical Analyzer 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef llex_h 8 | #define llex_h 9 | 10 | #include "lobject.h" 11 | #include "lzio.h" 12 | 13 | 14 | #define FIRST_RESERVED 257 15 | 16 | 17 | #if !defined(LUA_ENV) 18 | #define LUA_ENV "_ENV" 19 | #endif 20 | 21 | 22 | /* 23 | * WARNING: if you change the order of this enumeration, 24 | * grep "ORDER RESERVED" 25 | */ 26 | enum RESERVED { 27 | /* terminal symbols denoted by reserved words */ 28 | TK_AND = FIRST_RESERVED, TK_BREAK, 29 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, 30 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, 31 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, 32 | /* other terminal symbols */ 33 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, 34 | TK_SHL, TK_SHR, 35 | TK_DBCOLON, TK_EOS, 36 | TK_FLT, TK_INT, TK_NAME, TK_STRING 37 | }; 38 | 39 | /* number of reserved words */ 40 | #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) 41 | 42 | 43 | typedef union { 44 | lua_Number r; 45 | lua_Integer i; 46 | TString *ts; 47 | } SemInfo; /* semantics information */ 48 | 49 | 50 | typedef struct Token { 51 | int token; 52 | SemInfo seminfo; 53 | } Token; 54 | 55 | 56 | /* state of the lexer plus state of the parser when shared by all 57 | functions */ 58 | typedef struct LexState { 59 | int current; /* current character (charint) */ 60 | int linenumber; /* input line counter */ 61 | int lastline; /* line of last token 'consumed' */ 62 | Token t; /* current token */ 63 | Token lookahead; /* look ahead token */ 64 | struct FuncState *fs; /* current function (parser) */ 65 | struct lua_State *L; 66 | ZIO *z; /* input stream */ 67 | Mbuffer *buff; /* buffer for tokens */ 68 | Table *h; /* to avoid collection/reuse strings */ 69 | struct Dyndata *dyd; /* dynamic structures used by the parser */ 70 | TString *source; /* current source name */ 71 | TString *envn; /* environment variable name */ 72 | } LexState; 73 | 74 | 75 | LUAI_FUNC void luaX_init (lua_State *L); 76 | LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, 77 | TString *source, int firstchar); 78 | LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); 79 | LUAI_FUNC void luaX_next (LexState *ls); 80 | LUAI_FUNC int luaX_lookahead (LexState *ls); 81 | LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); 82 | LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /Mjolnir/lua/lmem.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lmem_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lgc.h" 20 | #include "lmem.h" 21 | #include "lobject.h" 22 | #include "lstate.h" 23 | 24 | 25 | 26 | /* 27 | ** About the realloc function: 28 | ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 29 | ** ('osize' is the old size, 'nsize' is the new size) 30 | ** 31 | ** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no 32 | ** matter 'x'). 33 | ** 34 | ** * frealloc(ud, p, x, 0) frees the block 'p' 35 | ** (in this specific case, frealloc must return NULL); 36 | ** particularly, frealloc(ud, NULL, 0, 0) does nothing 37 | ** (which is equivalent to free(NULL) in ISO C) 38 | ** 39 | ** frealloc returns NULL if it cannot create or reallocate the area 40 | ** (any reallocation to an equal or smaller size cannot fail!) 41 | */ 42 | 43 | 44 | 45 | #define MINSIZEARRAY 4 46 | 47 | 48 | void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, 49 | int limit, const char *what) { 50 | void *newblock; 51 | int newsize; 52 | if (*size >= limit/2) { /* cannot double it? */ 53 | if (*size >= limit) /* cannot grow even a little? */ 54 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); 55 | newsize = limit; /* still have at least one free place */ 56 | } 57 | else { 58 | newsize = (*size)*2; 59 | if (newsize < MINSIZEARRAY) 60 | newsize = MINSIZEARRAY; /* minimum size */ 61 | } 62 | newblock = luaM_reallocv(L, block, *size, newsize, size_elems); 63 | *size = newsize; /* update only when everything else is OK */ 64 | return newblock; 65 | } 66 | 67 | 68 | l_noret luaM_toobig (lua_State *L) { 69 | luaG_runerror(L, "memory allocation error: block too big"); 70 | } 71 | 72 | 73 | 74 | /* 75 | ** generic allocation routine. 76 | */ 77 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { 78 | void *newblock; 79 | global_State *g = G(L); 80 | size_t realosize = (block) ? osize : 0; 81 | lua_assert((realosize == 0) == (block == NULL)); 82 | #if defined(HARDMEMTESTS) 83 | if (nsize > realosize && g->gcrunning) 84 | luaC_fullgc(L, 1); /* force a GC whenever possible */ 85 | #endif 86 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); 87 | if (newblock == NULL && nsize > 0) { 88 | lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ 89 | if (g->version) { /* is state fully built? */ 90 | luaC_fullgc(L, 1); /* try to free some memory... */ 91 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ 92 | } 93 | if (newblock == NULL) 94 | luaD_throw(L, LUA_ERRMEM); 95 | } 96 | lua_assert((nsize == 0) == (newblock == NULL)); 97 | g->GCdebt = (g->GCdebt + nsize) - realosize; 98 | return newblock; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /Mjolnir/lua/lmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lmem_h 8 | #define lmem_h 9 | 10 | 11 | #include 12 | 13 | #include "llimits.h" 14 | #include "lua.h" 15 | 16 | 17 | /* 18 | ** This macro reallocs a vector 'b' from 'on' to 'n' elements, where 19 | ** each element has size 'e'. In case of arithmetic overflow of the 20 | ** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because 21 | ** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). 22 | ** 23 | ** (The macro is somewhat complex to avoid warnings: The 'sizeof' 24 | ** comparison avoids a runtime comparison when overflow cannot occur. 25 | ** The compiler should be able to optimize the real test by itself, but 26 | ** when it does it, it may give a warning about "comparison is always 27 | ** false due to limited range of data type"; the +1 tricks the compiler, 28 | ** avoiding this warning but also this optimization.) 29 | */ 30 | #define luaM_reallocv(L,b,on,n,e) \ 31 | (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ 32 | ? luaM_toobig(L) : cast_void(0)) , \ 33 | luaM_realloc_(L, (b), (on)*(e), (n)*(e))) 34 | 35 | /* 36 | ** Arrays of chars do not need any test 37 | */ 38 | #define luaM_reallocvchar(L,b,on,n) \ 39 | cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) 40 | 41 | #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) 42 | #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) 43 | #define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) 44 | 45 | #define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) 46 | #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) 47 | #define luaM_newvector(L,n,t) \ 48 | cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) 49 | 50 | #define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) 51 | 52 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ 53 | if ((nelems)+1 > (size)) \ 54 | ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) 55 | 56 | #define luaM_reallocvector(L, v,oldn,n,t) \ 57 | ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) 58 | 59 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); 60 | 61 | /* not to be called directly */ 62 | LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, 63 | size_t size); 64 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, 65 | size_t size_elem, int limit, 66 | const char *what); 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /Mjolnir/lua/lopcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Opcodes for Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lopcodes_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lopcodes.h" 16 | 17 | 18 | /* ORDER OP */ 19 | 20 | LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { 21 | "MOVE", 22 | "LOADK", 23 | "LOADKX", 24 | "LOADBOOL", 25 | "LOADNIL", 26 | "GETUPVAL", 27 | "GETTABUP", 28 | "GETTABLE", 29 | "SETTABUP", 30 | "SETUPVAL", 31 | "SETTABLE", 32 | "NEWTABLE", 33 | "SELF", 34 | "ADD", 35 | "SUB", 36 | "MUL", 37 | "MOD", 38 | "POW", 39 | "DIV", 40 | "IDIV", 41 | "BAND", 42 | "BOR", 43 | "BXOR", 44 | "SHL", 45 | "SHR", 46 | "UNM", 47 | "BNOT", 48 | "NOT", 49 | "LEN", 50 | "CONCAT", 51 | "JMP", 52 | "EQ", 53 | "LT", 54 | "LE", 55 | "TEST", 56 | "TESTSET", 57 | "CALL", 58 | "TAILCALL", 59 | "RETURN", 60 | "FORLOOP", 61 | "FORPREP", 62 | "TFORCALL", 63 | "TFORLOOP", 64 | "SETLIST", 65 | "CLOSURE", 66 | "VARARG", 67 | "EXTRAARG", 68 | NULL 69 | }; 70 | 71 | 72 | #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) 73 | 74 | LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { 75 | /* T A B C mode opcode */ 76 | opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ 77 | ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ 78 | ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ 79 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ 80 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ 81 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ 82 | ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ 83 | ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ 84 | ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ 85 | ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ 86 | ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ 87 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ 88 | ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ 89 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ 90 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ 91 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ 92 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ 93 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ 94 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ 95 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ 96 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ 97 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ 98 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ 99 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ 100 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ 101 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ 102 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ 103 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ 104 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ 105 | ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ 106 | ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ 107 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ 108 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ 109 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ 110 | ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ 111 | ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ 112 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ 113 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ 114 | ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ 115 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ 116 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ 117 | ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ 118 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ 119 | ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ 120 | ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ 121 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ 122 | ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ 123 | }; 124 | 125 | -------------------------------------------------------------------------------- /Mjolnir/lua/lparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Lua Parser 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lparser_h 8 | #define lparser_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* 16 | ** Expression and variable descriptor. 17 | ** Code generation for variables and expressions can be delayed to allow 18 | ** optimizations; An 'expdesc' structure describes a potentially-delayed 19 | ** variable/expression. It has a description of its "main" value plus a 20 | ** list of conditional jumps that can also produce its value (generated 21 | ** by short-circuit operators 'and'/'or'). 22 | */ 23 | 24 | /* kinds of variables/expressions */ 25 | typedef enum { 26 | VVOID, /* when 'expdesc' describes the last expression a list, 27 | this kind means an empty list (so, no expression) */ 28 | VNIL, /* constant nil */ 29 | VTRUE, /* constant true */ 30 | VFALSE, /* constant false */ 31 | VK, /* constant in 'k'; info = index of constant in 'k' */ 32 | VKFLT, /* floating constant; nval = numerical float value */ 33 | VKINT, /* integer constant; nval = numerical integer value */ 34 | VNONRELOC, /* expression has its value in a fixed register; 35 | info = result register */ 36 | VLOCAL, /* local variable; info = local register */ 37 | VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ 38 | VINDEXED, /* indexed variable; 39 | ind.vt = whether 't' is register or upvalue; 40 | ind.t = table register or upvalue; 41 | ind.idx = key's R/K index */ 42 | VJMP, /* expression is a test/comparison; 43 | info = pc of corresponding jump instruction */ 44 | VRELOCABLE, /* expression can put result in any register; 45 | info = instruction pc */ 46 | VCALL, /* expression is a function call; info = instruction pc */ 47 | VVARARG /* vararg expression; info = instruction pc */ 48 | } expkind; 49 | 50 | 51 | #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) 52 | #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) 53 | 54 | typedef struct expdesc { 55 | expkind k; 56 | union { 57 | lua_Integer ival; /* for VKINT */ 58 | lua_Number nval; /* for VKFLT */ 59 | int info; /* for generic use */ 60 | struct { /* for indexed variables (VINDEXED) */ 61 | short idx; /* index (R/K) */ 62 | lu_byte t; /* table (register or upvalue) */ 63 | lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ 64 | } ind; 65 | } u; 66 | int t; /* patch list of 'exit when true' */ 67 | int f; /* patch list of 'exit when false' */ 68 | } expdesc; 69 | 70 | 71 | /* description of active local variable */ 72 | typedef struct Vardesc { 73 | short idx; /* variable index in stack */ 74 | } Vardesc; 75 | 76 | 77 | /* description of pending goto statements and label statements */ 78 | typedef struct Labeldesc { 79 | TString *name; /* label identifier */ 80 | int pc; /* position in code */ 81 | int line; /* line where it appeared */ 82 | lu_byte nactvar; /* local level where it appears in current block */ 83 | } Labeldesc; 84 | 85 | 86 | /* list of labels or gotos */ 87 | typedef struct Labellist { 88 | Labeldesc *arr; /* array */ 89 | int n; /* number of entries in use */ 90 | int size; /* array size */ 91 | } Labellist; 92 | 93 | 94 | /* dynamic structures used by the parser */ 95 | typedef struct Dyndata { 96 | struct { /* list of active local variables */ 97 | Vardesc *arr; 98 | int n; 99 | int size; 100 | } actvar; 101 | Labellist gt; /* list of pending gotos */ 102 | Labellist label; /* list of active labels */ 103 | } Dyndata; 104 | 105 | 106 | /* control of blocks */ 107 | struct BlockCnt; /* defined in lparser.c */ 108 | 109 | 110 | /* state needed to generate code for a given function */ 111 | typedef struct FuncState { 112 | Proto *f; /* current function header */ 113 | struct FuncState *prev; /* enclosing function */ 114 | struct LexState *ls; /* lexical state */ 115 | struct BlockCnt *bl; /* chain of current blocks */ 116 | int pc; /* next position to code (equivalent to 'ncode') */ 117 | int lasttarget; /* 'label' of last 'jump label' */ 118 | int jpc; /* list of pending jumps to 'pc' */ 119 | int nk; /* number of elements in 'k' */ 120 | int np; /* number of elements in 'p' */ 121 | int firstlocal; /* index of first local var (in Dyndata array) */ 122 | short nlocvars; /* number of elements in 'f->locvars' */ 123 | lu_byte nactvar; /* number of active local variables */ 124 | lu_byte nups; /* number of upvalues */ 125 | lu_byte freereg; /* first free register */ 126 | } FuncState; 127 | 128 | 129 | LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 130 | Dyndata *dyd, const char *name, int firstchar); 131 | 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /Mjolnir/lua/lprefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Definitions for Lua code that must come before any other header file 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lprefix_h 8 | #define lprefix_h 9 | 10 | 11 | /* 12 | ** Allows POSIX/XSI stuff 13 | */ 14 | #if !defined(LUA_USE_C89) /* { */ 15 | 16 | #if !defined(_XOPEN_SOURCE) 17 | #define _XOPEN_SOURCE 600 18 | #elif _XOPEN_SOURCE == 0 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ 20 | #endif 21 | 22 | /* 23 | ** Allows manipulation of large files in gcc and some other compilers 24 | */ 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) 26 | #define _LARGEFILE_SOURCE 1 27 | #define _FILE_OFFSET_BITS 64 28 | #endif 29 | 30 | #endif /* } */ 31 | 32 | 33 | /* 34 | ** Windows stuff 35 | */ 36 | #if defined(_WIN32) /* { */ 37 | 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ 40 | #endif 41 | 42 | #endif /* } */ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /Mjolnir/lua/lstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** String table (keep all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstring_h 8 | #define lstring_h 9 | 10 | #include "lgc.h" 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) 16 | 17 | #define sizeludata(l) (sizeof(union UUdata) + (l)) 18 | #define sizeudata(u) sizeludata((u)->len) 19 | 20 | #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ 21 | (sizeof(s)/sizeof(char))-1)) 22 | 23 | 24 | /* 25 | ** test whether a string is a reserved word 26 | */ 27 | #define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) 28 | 29 | 30 | /* 31 | ** equality for short strings, which are always internalized 32 | */ 33 | #define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) 34 | 35 | 36 | LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); 37 | LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); 38 | LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 39 | LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 40 | LUAI_FUNC void luaS_clearcache (global_State *g); 41 | LUAI_FUNC void luaS_init (lua_State *L); 42 | LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); 43 | LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); 44 | LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); 45 | LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); 46 | LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); 47 | 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Mjolnir/lua/ltable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $ 3 | ** Lua tables (hash) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltable_h 8 | #define ltable_h 9 | 10 | #include "lobject.h" 11 | 12 | 13 | #define gnode(t,i) (&(t)->node[i]) 14 | #define gval(n) (&(n)->i_val) 15 | #define gnext(n) ((n)->i_key.nk.next) 16 | 17 | 18 | /* 'const' to avoid wrong writings that can mess up field 'next' */ 19 | #define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) 20 | 21 | /* 22 | ** writable version of 'gkey'; allows updates to individual fields, 23 | ** but not to the whole (which has incompatible type) 24 | */ 25 | #define wgkey(n) (&(n)->i_key.nk) 26 | 27 | #define invalidateTMcache(t) ((t)->flags = 0) 28 | 29 | 30 | /* true when 't' is using 'dummynode' as its hash part */ 31 | #define isdummy(t) ((t)->lastfree == NULL) 32 | 33 | 34 | /* allocated size for hash nodes */ 35 | #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) 36 | 37 | 38 | /* returns the key, given the value of a table entry */ 39 | #define keyfromval(v) \ 40 | (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) 41 | 42 | 43 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 44 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 45 | TValue *value); 46 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); 47 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); 48 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); 49 | LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); 50 | LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); 51 | LUAI_FUNC Table *luaH_new (lua_State *L); 52 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 53 | unsigned int nhsize); 54 | LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); 55 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); 56 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); 57 | LUAI_FUNC lua_Unsigned luaH_getn (Table *t); 58 | 59 | 60 | #if defined(LUA_DEBUG) 61 | LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); 62 | LUAI_FUNC int luaH_isdummy (const Table *t); 63 | #endif 64 | 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /Mjolnir/lua/ltm.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ltm_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lobject.h" 20 | #include "lstate.h" 21 | #include "lstring.h" 22 | #include "ltable.h" 23 | #include "ltm.h" 24 | #include "lvm.h" 25 | 26 | 27 | static const char udatatypename[] = "userdata"; 28 | 29 | LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { 30 | "no value", 31 | "nil", "boolean", udatatypename, "number", 32 | "string", "table", "function", udatatypename, "thread", 33 | "proto" /* this last case is used for tests only */ 34 | }; 35 | 36 | 37 | void luaT_init (lua_State *L) { 38 | static const char *const luaT_eventname[] = { /* ORDER TM */ 39 | "__index", "__newindex", 40 | "__gc", "__mode", "__len", "__eq", 41 | "__add", "__sub", "__mul", "__mod", "__pow", 42 | "__div", "__idiv", 43 | "__band", "__bor", "__bxor", "__shl", "__shr", 44 | "__unm", "__bnot", "__lt", "__le", 45 | "__concat", "__call" 46 | }; 47 | int i; 48 | for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); 50 | luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ 51 | } 52 | } 53 | 54 | 55 | /* 56 | ** function to be used with macro "fasttm": optimized for absence of 57 | ** tag methods 58 | */ 59 | const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { 60 | const TValue *tm = luaH_getshortstr(events, ename); 61 | lua_assert(event <= TM_EQ); 62 | if (ttisnil(tm)) { /* no tag method? */ 63 | events->flags |= cast_byte(1u<metatable; 75 | break; 76 | case LUA_TUSERDATA: 77 | mt = uvalue(o)->metatable; 78 | break; 79 | default: 80 | mt = G(L)->mt[ttnov(o)]; 81 | } 82 | return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); 83 | } 84 | 85 | 86 | /* 87 | ** Return the name of the type of an object. For tables and userdata 88 | ** with metatable, use their '__name' metafield, if present. 89 | */ 90 | const char *luaT_objtypename (lua_State *L, const TValue *o) { 91 | Table *mt; 92 | if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || 93 | (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { 94 | const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); 95 | if (ttisstring(name)) /* is '__name' a string? */ 96 | return getstr(tsvalue(name)); /* use it as type name */ 97 | } 98 | return ttypename(ttnov(o)); /* else use standard type name */ 99 | } 100 | 101 | 102 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 103 | const TValue *p2, TValue *p3, int hasres) { 104 | ptrdiff_t result = savestack(L, p3); 105 | StkId func = L->top; 106 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ 107 | setobj2s(L, func + 1, p1); /* 1st argument */ 108 | setobj2s(L, func + 2, p2); /* 2nd argument */ 109 | L->top += 3; 110 | if (!hasres) /* no result? 'p3' is third argument */ 111 | setobj2s(L, L->top++, p3); /* 3rd argument */ 112 | /* metamethod may yield only when called from Lua code */ 113 | if (isLua(L->ci)) 114 | luaD_call(L, func, hasres); 115 | else 116 | luaD_callnoyield(L, func, hasres); 117 | if (hasres) { /* if has result, move it to its place */ 118 | p3 = restorestack(L, result); 119 | setobjs2s(L, p3, --L->top); 120 | } 121 | } 122 | 123 | 124 | int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 125 | StkId res, TMS event) { 126 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ 127 | if (ttisnil(tm)) 128 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ 129 | if (ttisnil(tm)) return 0; 130 | luaT_callTM(L, tm, p1, p2, res, 1); 131 | return 1; 132 | } 133 | 134 | 135 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 136 | StkId res, TMS event) { 137 | if (!luaT_callbinTM(L, p1, p2, res, event)) { 138 | switch (event) { 139 | case TM_CONCAT: 140 | luaG_concaterror(L, p1, p2); 141 | /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ 142 | case TM_BAND: case TM_BOR: case TM_BXOR: 143 | case TM_SHL: case TM_SHR: case TM_BNOT: { 144 | lua_Number dummy; 145 | if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) 146 | luaG_tointerror(L, p1, p2); 147 | else 148 | luaG_opinterror(L, p1, p2, "perform bitwise operation on"); 149 | } 150 | /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ 151 | default: 152 | luaG_opinterror(L, p1, p2, "perform arithmetic on"); 153 | } 154 | } 155 | } 156 | 157 | 158 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, 159 | TMS event) { 160 | if (!luaT_callbinTM(L, p1, p2, L->top, event)) 161 | return -1; /* no metamethod */ 162 | else 163 | return !l_isfalse(L->top); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /Mjolnir/lua/ltm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltm_h 8 | #define ltm_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | /* 15 | * WARNING: if you change the order of this enumeration, 16 | * grep "ORDER TM" and "ORDER OP" 17 | */ 18 | typedef enum { 19 | TM_INDEX, 20 | TM_NEWINDEX, 21 | TM_GC, 22 | TM_MODE, 23 | TM_LEN, 24 | TM_EQ, /* last tag method with fast access */ 25 | TM_ADD, 26 | TM_SUB, 27 | TM_MUL, 28 | TM_MOD, 29 | TM_POW, 30 | TM_DIV, 31 | TM_IDIV, 32 | TM_BAND, 33 | TM_BOR, 34 | TM_BXOR, 35 | TM_SHL, 36 | TM_SHR, 37 | TM_UNM, 38 | TM_BNOT, 39 | TM_LT, 40 | TM_LE, 41 | TM_CONCAT, 42 | TM_CALL, 43 | TM_N /* number of elements in the enum */ 44 | } TMS; 45 | 46 | 47 | 48 | #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ 49 | ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) 50 | 51 | #define fasttm(l,et,e) gfasttm(G(l), et, e) 52 | 53 | #define ttypename(x) luaT_typenames_[(x) + 1] 54 | 55 | LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; 56 | 57 | 58 | LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); 59 | 60 | LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); 61 | LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, 62 | TMS event); 63 | LUAI_FUNC void luaT_init (lua_State *L); 64 | 65 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 66 | const TValue *p2, TValue *p3, int hasres); 67 | LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 68 | StkId res, TMS event); 69 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 70 | StkId res, TMS event); 71 | LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, 72 | const TValue *p2, TMS event); 73 | 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Mjolnir/lua/lua.hpp: -------------------------------------------------------------------------------- 1 | // lua.hpp 2 | // Lua header files for C++ 3 | // <> not supplied automatically because Lua also compiles as C++ 4 | 5 | extern "C" { 6 | #include "lua.h" 7 | #include "lualib.h" 8 | #include "lauxlib.h" 9 | } 10 | -------------------------------------------------------------------------------- /Mjolnir/lua/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | /* version suffix for environment variable names */ 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR 16 | 17 | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); 19 | 20 | #define LUA_COLIBNAME "coroutine" 21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 22 | 23 | #define LUA_TABLIBNAME "table" 24 | LUAMOD_API int (luaopen_table) (lua_State *L); 25 | 26 | #define LUA_IOLIBNAME "io" 27 | LUAMOD_API int (luaopen_io) (lua_State *L); 28 | 29 | #define LUA_OSLIBNAME "os" 30 | LUAMOD_API int (luaopen_os) (lua_State *L); 31 | 32 | #define LUA_STRLIBNAME "string" 33 | LUAMOD_API int (luaopen_string) (lua_State *L); 34 | 35 | #define LUA_UTF8LIBNAME "utf8" 36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 37 | 38 | #define LUA_BITLIBNAME "bit32" 39 | LUAMOD_API int (luaopen_bit32) (lua_State *L); 40 | 41 | #define LUA_MATHLIBNAME "math" 42 | LUAMOD_API int (luaopen_math) (lua_State *L); 43 | 44 | #define LUA_DBLIBNAME "debug" 45 | LUAMOD_API int (luaopen_debug) (lua_State *L); 46 | 47 | #define LUA_LOADLIBNAME "package" 48 | LUAMOD_API int (luaopen_package) (lua_State *L); 49 | 50 | 51 | /* open all previous libraries */ 52 | LUALIB_API void (luaL_openlibs) (lua_State *L); 53 | 54 | 55 | 56 | #if !defined(lua_assert) 57 | #define lua_assert(x) ((void)0) 58 | #endif 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Mjolnir/lua/lundump.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lundump_h 8 | #define lundump_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* data to catch conversion errors */ 16 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" 17 | 18 | #define LUAC_INT 0x5678 19 | #define LUAC_NUM cast_num(370.5) 20 | 21 | #define MYINT(s) (s[0]-'0') 22 | #define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) 23 | #define LUAC_FORMAT 0 /* this is the official format */ 24 | 25 | /* load one chunk; from lundump.c */ 26 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 27 | 28 | /* dump one chunk; from ldump.c */ 29 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 30 | void* data, int strip); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /Mjolnir/lua/lvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lvm_h 8 | #define lvm_h 9 | 10 | 11 | #include "ldo.h" 12 | #include "lobject.h" 13 | #include "ltm.h" 14 | 15 | 16 | #if !defined(LUA_NOCVTN2S) 17 | #define cvt2str(o) ttisnumber(o) 18 | #else 19 | #define cvt2str(o) 0 /* no conversion from numbers to strings */ 20 | #endif 21 | 22 | 23 | #if !defined(LUA_NOCVTS2N) 24 | #define cvt2num(o) ttisstring(o) 25 | #else 26 | #define cvt2num(o) 0 /* no conversion from strings to numbers */ 27 | #endif 28 | 29 | 30 | /* 31 | ** You can define LUA_FLOORN2I if you want to convert floats to integers 32 | ** by flooring them (instead of raising an error if they are not 33 | ** integral values) 34 | */ 35 | #if !defined(LUA_FLOORN2I) 36 | #define LUA_FLOORN2I 0 37 | #endif 38 | 39 | 40 | #define tonumber(o,n) \ 41 | (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) 42 | 43 | #define tointeger(o,i) \ 44 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) 45 | 46 | #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) 47 | 48 | #define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) 49 | 50 | 51 | /* 52 | ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, 53 | ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, 54 | ** return 0 (meaning it will have to check metamethod) with 'slot' 55 | ** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). 56 | ** 'f' is the raw get function to use. 57 | */ 58 | #define luaV_fastget(L,t,k,slot,f) \ 59 | (!ttistable(t) \ 60 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ 61 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ 62 | !ttisnil(slot))) /* result not nil? */ 63 | 64 | /* 65 | ** standard implementation for 'gettable' 66 | */ 67 | #define luaV_gettable(L,t,k,v) { const TValue *slot; \ 68 | if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ 69 | else luaV_finishget(L,t,k,v,slot); } 70 | 71 | 72 | /* 73 | ** Fast track for set table. If 't' is a table and 't[k]' is not nil, 74 | ** call GC barrier, do a raw 't[k]=v', and return true; otherwise, 75 | ** return false with 'slot' equal to NULL (if 't' is not a table) or 76 | ** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro 77 | ** returns true, there is no need to 'invalidateTMcache', because the 78 | ** call is not creating a new entry. 79 | */ 80 | #define luaV_fastset(L,t,k,slot,f,v) \ 81 | (!ttistable(t) \ 82 | ? (slot = NULL, 0) \ 83 | : (slot = f(hvalue(t), k), \ 84 | ttisnil(slot) ? 0 \ 85 | : (luaC_barrierback(L, hvalue(t), v), \ 86 | setobj2t(L, cast(TValue *,slot), v), \ 87 | 1))) 88 | 89 | 90 | #define luaV_settable(L,t,k,v) { const TValue *slot; \ 91 | if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ 92 | luaV_finishset(L,t,k,v,slot); } 93 | 94 | 95 | 96 | LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); 97 | LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); 98 | LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); 99 | LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); 100 | LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); 101 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, 102 | StkId val, const TValue *slot); 103 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 104 | StkId val, const TValue *slot); 105 | LUAI_FUNC void luaV_finishOp (lua_State *L); 106 | LUAI_FUNC void luaV_execute (lua_State *L); 107 | LUAI_FUNC void luaV_concat (lua_State *L, int total); 108 | LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); 109 | LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); 110 | LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); 111 | LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /Mjolnir/lua/lzio.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lzio_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "llimits.h" 18 | #include "lmem.h" 19 | #include "lstate.h" 20 | #include "lzio.h" 21 | 22 | 23 | int luaZ_fill (ZIO *z) { 24 | size_t size; 25 | lua_State *L = z->L; 26 | const char *buff; 27 | lua_unlock(L); 28 | buff = z->reader(L, z->data, &size); 29 | lua_lock(L); 30 | if (buff == NULL || size == 0) 31 | return EOZ; 32 | z->n = size - 1; /* discount char being returned */ 33 | z->p = buff; 34 | return cast_uchar(*(z->p++)); 35 | } 36 | 37 | 38 | void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { 39 | z->L = L; 40 | z->reader = reader; 41 | z->data = data; 42 | z->n = 0; 43 | z->p = NULL; 44 | } 45 | 46 | 47 | /* --------------------------------------------------------------- read --- */ 48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { 49 | while (n) { 50 | size_t m; 51 | if (z->n == 0) { /* no bytes in buffer? */ 52 | if (luaZ_fill(z) == EOZ) /* try to read more */ 53 | return n; /* no more input; return number of missing bytes */ 54 | else { 55 | z->n++; /* luaZ_fill consumed first byte; put it back */ 56 | z->p--; 57 | } 58 | } 59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ 60 | memcpy(b, z->p, m); 61 | z->n -= m; 62 | z->p += m; 63 | b = (char *)b + m; 64 | n -= m; 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Mjolnir/lua/lzio.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lzio_h 9 | #define lzio_h 10 | 11 | #include "lua.h" 12 | 13 | #include "lmem.h" 14 | 15 | 16 | #define EOZ (-1) /* end of stream */ 17 | 18 | typedef struct Zio ZIO; 19 | 20 | #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) 21 | 22 | 23 | typedef struct Mbuffer { 24 | char *buffer; 25 | size_t n; 26 | size_t buffsize; 27 | } Mbuffer; 28 | 29 | #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30 | 31 | #define luaZ_buffer(buff) ((buff)->buffer) 32 | #define luaZ_sizebuffer(buff) ((buff)->buffsize) 33 | #define luaZ_bufflen(buff) ((buff)->n) 34 | 35 | #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) 36 | #define luaZ_resetbuffer(buff) ((buff)->n = 0) 37 | 38 | 39 | #define luaZ_resizebuffer(L, buff, size) \ 40 | ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ 41 | (buff)->buffsize, size), \ 42 | (buff)->buffsize = size) 43 | 44 | #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) 45 | 46 | 47 | LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, 48 | void *data); 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 50 | 51 | 52 | 53 | /* --------- Private Part ------------------ */ 54 | 55 | struct Zio { 56 | size_t n; /* bytes still unread */ 57 | const char *p; /* current position in buffer */ 58 | lua_Reader reader; /* reader function */ 59 | void *data; /* additional data */ 60 | lua_State *L; /* Lua state (for reader) */ 61 | }; 62 | 63 | 64 | LUAI_FUNC int luaZ_fill (ZIO *z); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /Mjolnir/setup.lua: -------------------------------------------------------------------------------- 1 | local prettypath, fullpath, configdir, hasinitfile = ... 2 | 3 | os.exit = mjolnir._exit 4 | 5 | local function runstring(s) 6 | local fn, err = load("return " .. s) 7 | if not fn then fn, err = load(s) end 8 | if not fn then return tostring(err) end 9 | 10 | local str = "" 11 | local results = table.pack(pcall(fn)) 12 | for i = 2,results.n do 13 | if i > 2 then str = str .. "\t" end 14 | str = str .. tostring(results[i]) 15 | end 16 | return str 17 | end 18 | 19 | --- mjolnir.configdir = "~/.mjolnir/" 20 | --- Constant 21 | --- The user's Mjolnir config directory. Modules may use it, assuming 22 | --- they've worked out a contract with the user about how to use it. 23 | mjolnir.configdir = configdir 24 | 25 | --- mjolnir.showerror(err) 26 | --- Function 27 | --- 28 | --- Presents an error to the user via Mjolnir's GUI. The default 29 | --- implementation prints the error, focuses Mjolnir, and opens 30 | --- Mjolnir's console. 31 | --- 32 | --- Users can override this with a new function that shows errors in a 33 | --- custom way. 34 | --- 35 | --- Modules can call this in the event of an error, e.g. in callbacks 36 | --- from the user: 37 | --- 38 | --- local ok, err = xpcall(callbackfn, debug.traceback) 39 | --- if not ok then mjolnir.showerror(err) end 40 | function mjolnir.showerror(err) 41 | mjolnir._notify("Mjolnir error occurred") -- undecided on this line 42 | print(err) 43 | mjolnir.focus() 44 | mjolnir.openconsole() 45 | end 46 | 47 | --- mjolnir.rawprint = print 48 | --- Function 49 | --- The original print function, before Mjolnir overrides it. 50 | local rawprint = print 51 | mjolnir.rawprint = rawprint 52 | function print(...) 53 | rawprint(...) 54 | local vals = table.pack(...) 55 | 56 | for k = 1, vals.n do 57 | vals[k] = tostring(vals[k]) 58 | end 59 | 60 | local str = table.concat(vals, "\t") .. "\n" 61 | mjolnir._logmessage(str) 62 | end 63 | 64 | if not hasinitfile then 65 | print(string.format("-- Can't find %s; create it and reload your config.", prettypath)) 66 | return runstring 67 | end 68 | 69 | print("-- Loading " .. prettypath) 70 | local fn, err = loadfile(fullpath) 71 | if not fn then mjolnir.showerror(err) return runstring end 72 | 73 | local ok, err = xpcall(fn, debug.traceback) 74 | if not ok then mjolnir.showerror(err) return runstring end 75 | 76 | print "-- Done." 77 | 78 | return runstring 79 | -------------------------------------------------------------------------------- /Mjolnir/statusicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/statusicon.png -------------------------------------------------------------------------------- /Mjolnir/statusicon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/Mjolnir/statusicon@2x.png -------------------------------------------------------------------------------- /Mjolnir/variables.h: -------------------------------------------------------------------------------- 1 | #ifndef Mjolnir_variables_h 2 | #define Mjolnir_variables_h 3 | 4 | 5 | static NSString* MJReleaseNotesURL = @"https://github.com/sdegutis/mjolnir#changes"; 6 | static NSString* MJDownloadPage = @"https://github.com/sdegutis/mjolnir/releases/latest"; 7 | static NSString* MJUpdatesURL = @"https://raw.githubusercontent.com/sdegutis/mjolnir/master/LATESTVERSION"; 8 | 9 | static NSString* MJPublicKey = @"" 10 | "-----BEGIN PUBLIC KEY-----\n" 11 | "MIIBtzCCASsGByqGSM44BAEwggEeAoGBAKI1LKQiFEWu6woOAzKPeVrvMoUFLv43\n" 12 | "I2PYizYCAUkzdh8Rgos0qSwg6+qaStVB3SYHxXlwtyiuJwm9CZtiPJzXUFDESvha\n" 13 | "hJckBRxL93zrUIW1gCIeXrvX89ZNzn9pgj6c72z+rkfV/SFYYXWNm375t6gZwoTy\n" 14 | "rlZVNnUewetvAhUAhUtGFpd0rJmqhaMEuPRDDUQGlhkCgYBEm3G1/p058vDw8rKW\n" 15 | "u0UKHN6syEATqditlyqcH0F28pxwVTXIt44o9nrygDdSgcZne2GQC6PJU1tSDliH\n" 16 | "77nJGCvfJ6Uyj69ieAY3q7Enshk5M3rBub+Nq5Ec0YtpuDVUB6ytXnwpld/bbOQ3\n" 17 | "WlMqy6lTidH72azA1+UVcSOLXQOBhQACgYEAmV6CvXE5N1gScnbD+5E4VM4JFyF8\n" 18 | "xjA+0xzpoW2ctFKvgQxMswlmvvZvU7oTm/KHrJkK8arlWi3kV2qfNk1Ry7GKE9fW\n" 19 | "jebNdfI+fWntQjd1bCIlACFGrH5ioucI0Hdzxarx/7Ie10UPveSRf8ifO9JU1bSH\n" 20 | "cohzwU5/305uivg=\n" 21 | "-----END PUBLIC KEY-----\n"; 22 | 23 | #define MJCheckForUpdatesKey @"MJCheckForUpdatesKey" 24 | #define MJShowDockIconKey @"MJShowDockIconKey" 25 | #define MJShowMenuIconKey @"MJShowMenuIconKey" 26 | #define MJKeepConsoleOnTopKey @"MJKeepConsoleOnTopKey" 27 | #define MJHasRunAlreadyKey @"MJHasRunAlreadyKey" 28 | #define MJCheckForUpdatesIntervalKey @"MJCheckForUpdatesIntervalKey" 29 | 30 | static NSString* MJConfigFile = @"~/.mjolnir/init.lua"; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'github-markdown' 4 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | github-markdown (0.6.6) 5 | 6 | PLATFORMS 7 | ruby 8 | 9 | DEPENDENCIES 10 | github-markdown 11 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | all: build/Mjolnir.tgz 2 | 3 | build/Mjolnir.tgz: build/Mjolnir.docset 4 | tar --exclude='.DS_Store' -cvzf $@ -C build Mjolnir.docset 5 | 6 | build/Mjolnir.docset: build/docs.sql.out build/docs.html.d 7 | rm -rf $@ 8 | cp -R templates/Mjolnir.docset $@ 9 | cp build/docs.sql.out $@/Contents/Resources/docSet.dsidx 10 | cp build/docs.html.d/* $@/Contents/Resources/Documents/ 11 | 12 | build/docs.html.d: build/docs.json 13 | mkdir -p $@ 14 | rm -f $@/* 15 | bin/genhtml $@ < $< 16 | 17 | build/docs.sql.out: build/docs.sql 18 | sqlite3 $@ < $< 19 | 20 | build/docs.sql: build/docs.json 21 | bin/gensql < $< > $@ 22 | 23 | build/docs.json: build/comments.json 24 | bin/genjson < $< > $@ 25 | 26 | build/comments.json: build/candidates.txt 27 | bin/gencomments < $< > $@ 28 | 29 | build/candidates.txt: build/candidates 30 | find $< -type f \( -name '*.lua' -o -name '*.m' \) -not -path '*/_docsignore/*' -exec cat {} + > $@ 31 | 32 | build/candidates: build/repos.txt 33 | mkdir -p $@ 34 | bin/download $@ < $< 35 | 36 | build/repos.txt: build/wiki 37 | cp build/wiki/Repos.md $@ 38 | 39 | build/wiki: 40 | git clone https://github.com/sdegutis/mjolnir.wiki.git $@ 41 | 42 | clean: 43 | rm -rf build/* 44 | 45 | .PHONY: all clean 46 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ### To write docs 2 | 3 | 1. Any comment that starts with `---` or `///` is a doc-string (i.e. 3 comment-characters in a row) 4 | 2. Doc-strings continue on until a non-docstring line 5 | 3. Doc-strings for modules contain `=== my.modulename ===`, then any number of lines describing it 6 | 4. Doc-strings for items (functions, variables, etc.) go like this: 7 | 1. The first line starts with `my.modulename.item` or `my.modulename:item` -- this is the item name 8 | 2. Any non-alphanumeric character ends the item name and is ignored, i.e. parentheses or spaces: 9 | 1. `my.modulename:foo()` 10 | 2. `my.modulename:foo(bar) -> string` 11 | 3. `my.modulename.foo(bar, fn(int) -> int)` 12 | 4. `my.modulename.foo = {}` 13 | 3. The second line is a single captitalized word, like "Variable" or "Function" or "Method" 14 | 4. The remaining lines describe the item 15 | 5. Any comment that starts with 4 comment-characters is ignored 16 | 6. Anything in a directory `_docsignore` or subdirectory of it are skipped 17 | 7. Only files ending in `.lua` or `.m` are scanned 18 | 19 | ### To generate docs 20 | 21 | ~~~bash 22 | $ bundle install 23 | $ make 24 | ~~~ 25 | 26 | ### To add your module 27 | 28 | 1. Add your repo's `.tar.gz` URL to Repos page in this wiki 29 | 2. Clone this repo 30 | 3. Generate docs (see above) 31 | 4. Verify the built Mjolnir.docset looks like it should 32 | 5. Send PR to https://github.com/kapeli/Dash-User-Contributions 33 | 1. Fork his repo 34 | 2. Copy `build/Mjolnir.tgz` (from step #3) into `Dash-User-Contributions/docsets/Mjolnir/` 35 | 3. Update the version number in `Dash-User-Contributions/docsets/Mjolnir/docset.json` 36 | 4. Send PR on our behalf 37 | -------------------------------------------------------------------------------- /docs/bin/download: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | DEST=$1 3 | while read -r url; do 4 | url=$(echo $url | tr -d '\r') 5 | echo "### Cloning [${url}] to $DEST" 6 | curl -L -s $url | tar -x -C $DEST 7 | done 8 | -------------------------------------------------------------------------------- /docs/bin/gencomments: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | Encoding.default_external = Encoding::UTF_8 3 | Encoding.default_internal = Encoding::UTF_8 4 | 5 | require 'json' 6 | 7 | comments = [] 8 | 9 | partialcomment = [] 10 | incomment = false 11 | 12 | STDIN.read.split("\n").each do |line| 13 | islua = line.start_with?('-'*3) and !line.start_with?('-'*4) 14 | isobjc = line.start_with?('/'*3) and !line.start_with?('/'*4) 15 | 16 | if islua || isobjc then 17 | incomment = true 18 | partialcomment << line[3..-1].sub(/^\s/, '') 19 | elsif incomment then 20 | incomment = false 21 | comments << partialcomment 22 | partialcomment = [] 23 | end 24 | end 25 | 26 | puts JSON.pretty_generate(comments) 27 | -------------------------------------------------------------------------------- /docs/bin/genhtml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'json' 3 | require 'github/markdown' 4 | require 'erb' 5 | 6 | outdir = ARGV.first 7 | docmods = JSON.load(STDIN.read) 8 | 9 | mod_template = ERB.new(File.read('templates/ext.html.erb')) 10 | index_template = ERB.new(File.read('templates/index.html.erb')) 11 | 12 | content = GitHub::Markdown.render_gfm(File.read('templates/index.md')) 13 | html = index_template.result(binding) 14 | File.write("#{outdir}/index.html", html) 15 | 16 | docmods.each do |mod| 17 | File.write("#{outdir}/#{mod['name']}.html", mod_template.result(binding)) 18 | end 19 | -------------------------------------------------------------------------------- /docs/bin/genjson: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'json' 3 | 4 | comments = JSON.load(STDIN.read) 5 | 6 | newmod = ->(c) {{name: c[0].gsub('=', '').strip, 7 | doc: c[1..-1].join("\n").strip, 8 | items: []}} 9 | 10 | newitem = ->(c) {{type: c[1], 11 | name: nil, 12 | def: c[0], 13 | doc: c[2..-1].join("\n").strip}} 14 | 15 | ismod = ->(c) { c[0].include?('===') } 16 | mods = comments.select(&ismod).map(&newmod) 17 | items = comments.reject(&ismod).map(&newitem) 18 | orderedmods = mods.sort_by{|m|m[:name]}.reverse 19 | 20 | items.each do |item| 21 | mod = orderedmods.find{|mod| item[:def].start_with?(mod[:name])} 22 | if mod.nil? 23 | abort "error: couldn't find module for #{item[:def]}" 24 | end 25 | item[:name] = item[:def][(mod[:name].size+1)..-1].match(/\w+/)[0] 26 | mod[:items] << item 27 | end 28 | 29 | mods.sort_by!{|m|m[:name]} 30 | puts JSON.pretty_generate(mods) 31 | -------------------------------------------------------------------------------- /docs/bin/gensql: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'json' 3 | 4 | docmods = JSON.load(STDIN.read) 5 | 6 | puts "CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);" 7 | puts "CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);" 8 | 9 | docmods.each do |mod| 10 | mod['items'].each do |item| 11 | puts "INSERT INTO searchIndex VALUES (NULL, '#{mod['name']}.#{item['name']}', '#{item['type']}', '#{mod['name']}.html##{item['name']}');" 12 | end 13 | puts "INSERT INTO searchIndex VALUES (NULL, '#{mod['name']}', 'Module', '#{mod['name']}.html');" 14 | end 15 | -------------------------------------------------------------------------------- /docs/templates/Mjolnir.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | mjolnir 7 | CFBundleName 8 | Mjolnir 9 | DocSetPlatformFamily 10 | mjolnir 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | DashDocSetFamily 16 | dashtoc 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/templates/Mjolnir.docset/Contents/Resources/Documents/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/docs/templates/Mjolnir.docset/Contents/Resources/Documents/.gitkeep -------------------------------------------------------------------------------- /docs/templates/Mjolnir.docset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/docs/templates/Mjolnir.docset/icon.png -------------------------------------------------------------------------------- /docs/templates/Mjolnir.docset/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/docs/templates/Mjolnir.docset/icon@2x.png -------------------------------------------------------------------------------- /docs/templates/ext.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mjolnir docs: <%= mod['name'] %> module 4 | 10 | 11 | 12 |
13 |

<%= mod['name'] %>

14 | <%= GitHub::Markdown.render_gfm(mod['doc']) %> 15 |
16 | <% mod['items'].sort_by{|m|m['def']}.each do |item| %> 17 |
18 | 19 |

<%= item['name'] %>

20 | <%= item['def'] %> 21 | <%= GitHub::Markdown.render_gfm(item['doc']) %> 22 |
23 | <% end %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/templates/index.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mjolnir docs 4 | 9 | 10 | 11 |
12 |

Mjolnir.app

13 |
14 |
15 | <%= content %> 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/templates/index.md: -------------------------------------------------------------------------------- 1 | ### Project links 2 | 3 | Resource | Link 4 | -------------------------|--------------------------------------------------- 5 | Fancy Website | http://mjolnir.io/ 6 | Github page | https://github.com/sdegutis/mjolnir/ 7 | Mailing List | https://groups.google.com/forum/#!forum/mjolnir-io 8 | IRC channel | #mjolnir on freenode 9 | -------------------------------------------------------------------------------- /mods/LICENSE.md: -------------------------------------------------------------------------------- 1 | > Released under MIT license. 2 | > 3 | > Copyright (c) 2013 Steven Degutis 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /mods/README.md: -------------------------------------------------------------------------------- 1 | Fundamental Lua modules for [Mjolnir](https://github.com/sdegutis/mjolnir). 2 | 3 | You can find them here: https://rocks.moonscript.org/search?q=mjolnir 4 | -------------------------------------------------------------------------------- /mods/alert/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/alert/mjolnir.alert-0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.alert" 2 | version = "0.2-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to show brief messages on-screen." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | ["mjolnir.alert"] = "alert.m", 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /mods/application/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/application/application.h: -------------------------------------------------------------------------------- 1 | #ifndef Application_application_h 2 | #define Application_application_h 3 | 4 | static void new_application(lua_State* L, pid_t pid) { 5 | AXUIElementRef* appptr = lua_newuserdata(L, sizeof(AXUIElementRef)); 6 | *appptr = AXUIElementCreateApplication(pid); 7 | 8 | luaL_getmetatable(L, "mjolnir.application"); 9 | lua_setmetatable(L, -2); 10 | 11 | lua_newtable(L); 12 | lua_pushnumber(L, pid); 13 | lua_setfield(L, -2, "pid"); 14 | lua_setuservalue(L, -2); 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /mods/application/application.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.application === 2 | --- 3 | --- Manipulate running applications. 4 | 5 | local application = require "mjolnir.application.internal" 6 | local fnutils = require "mjolnir.fnutils" 7 | local window = require "mjolnir.window" 8 | 9 | --- mjolnir.application:visiblewindows() -> win[] 10 | --- Method 11 | --- Returns only the app's windows that are visible. 12 | function application:visiblewindows() 13 | return fnutils.filter(self:allwindows(), window.isvisible) 14 | end 15 | 16 | --- mjolnir.application:activate(allwindows = false) -> bool 17 | --- Method 18 | --- Tries to activate the app (make its key window focused) and returns whether it succeeded; if allwindows is true, all windows of the application are brought forward as well. 19 | function application:activate(allwindows) 20 | if self:isunresponsive() then return false end 21 | local win = self:_focusedwindow() 22 | if win then 23 | return win:becomemain() and self:_bringtofront(allwindows) 24 | else 25 | return self:_activate(allwindows) 26 | end 27 | end 28 | 29 | return application 30 | -------------------------------------------------------------------------------- /mods/application/mjolnir.application-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.application" 2 | version = "0.3-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to inspect and manipulate running applications and their windows." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | "mjolnir.fnutils", 16 | "mjolnir.geometry", 17 | "mjolnir.screen", 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | ["mjolnir.application"] = "application.lua", 23 | ["mjolnir.application.internal"] = "application.m", 24 | ["mjolnir.window"] = "window.lua", 25 | ["mjolnir.window.internal"] = "window.m", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /mods/application/window.h: -------------------------------------------------------------------------------- 1 | #ifndef Window_application_h 2 | #define Window_application_h 3 | 4 | #import 5 | #import 6 | 7 | static void new_window(lua_State* L, AXUIElementRef win) { 8 | AXUIElementRef* winptr = lua_newuserdata(L, sizeof(AXUIElementRef)); 9 | *winptr = win; 10 | 11 | luaL_getmetatable(L, "mjolnir.window"); 12 | lua_setmetatable(L, -2); 13 | 14 | lua_newtable(L); 15 | lua_setuservalue(L, -2); 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /mods/fnutils/.gitignore: -------------------------------------------------------------------------------- 1 | # LuaRocks 2 | *.o 3 | *.so 4 | *.rock 5 | -------------------------------------------------------------------------------- /mods/fnutils/fnutils.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.fnutils === 2 | --- 3 | --- Super-helpful functional programming utilities. 4 | 5 | local fnutils = {} 6 | 7 | 8 | --- mjolnir.fnutils.map(t, fn) -> t 9 | --- Function 10 | --- Returns a table of the results of fn(el) on every el in t. 11 | function fnutils.map(t, fn) 12 | local nt = {} 13 | for k, v in pairs(t) do 14 | table.insert(nt, fn(v) or nil) 15 | end 16 | return nt 17 | end 18 | 19 | --- mjolnir.fnutils.each(t, fn) -> t 20 | --- Function 21 | --- Runs fn(el) for every el in t. 22 | function fnutils.each(t, fn) 23 | for k, v in pairs(t) do 24 | fn(v) 25 | end 26 | end 27 | 28 | --- mjolnir.fnutils.filter(t, fn) -> t 29 | --- Function 30 | --- Returns a table of the elements in t in which fn(el) is truthy. 31 | function fnutils.filter(t, fn) 32 | local nt = {} 33 | for k, v in pairs(t) do 34 | if fn(v) then table.insert(nt, v) end 35 | end 36 | return nt 37 | end 38 | 39 | --- mjolnir.fnutils.copy(t) -> t2 40 | --- Function 41 | --- Returns a new copy of t using pairs(t). 42 | function fnutils.copy(t) 43 | local nt = {} 44 | for k, v in pairs(t) do 45 | nt[k] = v 46 | end 47 | return nt 48 | end 49 | 50 | --- mjolnir.fnutils.contains(t, el) -> bool 51 | --- Function 52 | --- Returns whether the table contains the given element. 53 | function fnutils.contains(t, el) 54 | for k, v in pairs(t) do 55 | if v == el then 56 | return true 57 | end 58 | end 59 | return false 60 | end 61 | 62 | --- mjolnir.fnutils.indexof(t, el) -> int or nil 63 | --- Function 64 | --- Returns the index of a given element in a table, or nil if not found. 65 | function fnutils.indexof(t, el) 66 | for k, v in pairs(t) do 67 | if v == el then 68 | return k 69 | end 70 | end 71 | return nil 72 | end 73 | 74 | --- mjolnir.fnutils.concat(t1, t2) 75 | --- Function 76 | --- Adds all elements of t2 to the end of t1. 77 | function fnutils.concat(t1, t2) 78 | for i = 1, #t2 do 79 | t1[#t1 + 1] = t2[i] 80 | end 81 | return t1 82 | end 83 | 84 | --- mjolnir.fnutils.mapcat(t, fn) -> t2 85 | --- Function 86 | --- Runs fn(el) for every el in t, and assuming the results are tables, combines them into a new table. 87 | function fnutils.mapcat(t, fn) 88 | local nt = {} 89 | for k, v in pairs(t) do 90 | fnutils.concat(nt, fn(v)) 91 | end 92 | return nt 93 | end 94 | 95 | --- mjolnir.fnutils.reduce(t, fn) -> t2 96 | --- Function 97 | --- Runs fn(el1, el2) for every el in t, then fn(result, el3), etc, until there's only one left. 98 | function fnutils.reduce(t, fn) 99 | local len = #t 100 | if len == 0 then return nil end 101 | if len == 1 then return t[1] end 102 | 103 | local result = t[1] 104 | for i = 2, #t do 105 | result = fn(result, t[i]) 106 | end 107 | return result 108 | end 109 | 110 | --- mjolnir.fnutils.find(t, fn) -> el 111 | --- Function 112 | --- Returns the first element where fn(el) is truthy. 113 | function fnutils.find(t, fn) 114 | for _, v in pairs(t) do 115 | if fn(v) then return v end 116 | end 117 | return nil 118 | end 119 | 120 | --- mjolnir.fnutils.sequence(...) -> fn 121 | --- Function 122 | --- Returns a list of the results of the passed functions. 123 | function fnutils.sequence(...) 124 | local arg = table.pack(...) 125 | return function() 126 | local results = {} 127 | for _, fn in ipairs(arg) do 128 | table.insert(results, fn()) 129 | end 130 | return results 131 | end 132 | end 133 | 134 | --- mjolnir.fnutils.partial(fn, ...) -> fn' 135 | --- Function 136 | --- Returns fn partially applied to arg (...). 137 | function fnutils.partial(fn, ...) 138 | local args = table.pack(...) 139 | return function(...) 140 | for idx, val in ipairs(table.pack(...)) do 141 | args[args.n + idx] = val 142 | end 143 | return fn(table.unpack(args)) 144 | end 145 | end 146 | 147 | --- mjolnir.fnutils.cycle(t) -> fn() -> t[n] 148 | --- Function 149 | --- Returns a function that returns t[1], t[2], ... t[#t], t[1], ... on successive calls. 150 | --- Example: 151 | --- f = cycle({4, 5, 6}) 152 | --- {f(), f(), f(), f(), f(), f(), f()} == {4, 5, 6, 4, 5, 6, 4} 153 | function fnutils.cycle(t) 154 | local i = 1 155 | return function() 156 | local x = t[i] 157 | i = i % #t + 1 158 | return x 159 | end 160 | end 161 | 162 | return fnutils 163 | -------------------------------------------------------------------------------- /mods/fnutils/mjolnir.fnutils-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.fnutils" 2 | version = "0.1-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to help with functional programming." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | ["mjolnir.fnutils"] = "fnutils.lua", 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /mods/geometry/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/geometry/geometry.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.geometry === 2 | --- 3 | --- Mathy stuff. 4 | 5 | local geometry = require "mjolnir.geometry.internal" 6 | 7 | --- mjolnir.geometry.rotateccw(point, aroundpoint, ntimes = 1) -> point 8 | --- Function 9 | --- Rotates a point around another point N times. 10 | function geometry.rotateccw(point, aroundpoint, ntimes) 11 | local p = {x = point.x, y = point.y} 12 | for i = 1, ntimes or 1 do 13 | local px = p.x 14 | p.x = (aroundpoint.x - (p.y - aroundpoint.y)) 15 | p.y = (aroundpoint.y + (px - aroundpoint.x)) 16 | end 17 | return p 18 | end 19 | 20 | --- mjolnir.geometry.hypot(point) -> number 21 | --- Function 22 | --- Returns hypotenuse of a line defined from 0,0 to point. 23 | function geometry.hypot(p) 24 | return math.sqrt(p.x * p.x + p.y * p.y) 25 | end 26 | 27 | --- mjolnir.geometry.rect(x, y, w, h) -> rect 28 | --- Constructor 29 | --- Convenience function for creating a rect-table. 30 | function geometry.rect(x, y, w, h) 31 | return {x = x, y = y, w = w, h = h} 32 | end 33 | 34 | --- mjolnir.geometry.point(x, y) -> point 35 | --- Constructor 36 | --- Convenience function for creating a point-table. 37 | function geometry.point(x, y) 38 | return {x = x, y = y} 39 | end 40 | 41 | --- mjolnir.geometry.size(w, h) -> size 42 | --- Constructor 43 | --- Convenience function for creating a size-table. 44 | function geometry.size(w, h) 45 | return {w = w, h = h} 46 | end 47 | 48 | return geometry 49 | -------------------------------------------------------------------------------- /mods/geometry/geometry.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | static NSRect geom_torect(lua_State* L, int idx) { 5 | luaL_checktype(L, idx, LUA_TTABLE); 6 | CGFloat x = (lua_getfield(L, idx, "x"), luaL_checknumber(L, -1)); 7 | CGFloat y = (lua_getfield(L, idx, "y"), luaL_checknumber(L, -1)); 8 | CGFloat w = (lua_getfield(L, idx, "w"), luaL_checknumber(L, -1)); 9 | CGFloat h = (lua_getfield(L, idx, "h"), luaL_checknumber(L, -1)); 10 | lua_pop(L, 4); 11 | return NSMakeRect(x, y, w, h); 12 | } 13 | 14 | void geom_pushpoint(lua_State* L, NSPoint point) { 15 | lua_newtable(L); 16 | lua_pushnumber(L, point.x); lua_setfield(L, -2, "x"); 17 | lua_pushnumber(L, point.y); lua_setfield(L, -2, "y"); 18 | } 19 | 20 | static void geom_pushrect(lua_State* L, NSRect rect) { 21 | lua_newtable(L); 22 | lua_pushnumber(L, rect.origin.x); lua_setfield(L, -2, "x"); 23 | lua_pushnumber(L, rect.origin.y); lua_setfield(L, -2, "y"); 24 | lua_pushnumber(L, rect.size.width); lua_setfield(L, -2, "w"); 25 | lua_pushnumber(L, rect.size.height); lua_setfield(L, -2, "h"); 26 | } 27 | 28 | /// mjolnir.geometry.intersectionrect(rect1, rect2) -> rect3 29 | /// Function 30 | /// Returns the intersection of two rects as a new rect. 31 | static int geometry_intersectionrect(lua_State* L) { 32 | NSRect r1 = geom_torect(L, 1); 33 | NSRect r2 = geom_torect(L, 2); 34 | geom_pushrect(L, NSIntersectionRect(r1, r2)); 35 | return 1; 36 | } 37 | 38 | /// mjolnir.geometry.rectmidpoint(rect) -> point 39 | /// Function 40 | /// Returns the midpoint of a rect. 41 | static int geometry_rectmidpoint(lua_State* L) { 42 | NSRect r = geom_torect(L, 1); 43 | geom_pushpoint(L, NSMakePoint(NSMidX(r), NSMidY(r))); 44 | return 1; 45 | } 46 | 47 | 48 | static const luaL_Reg geometrylib[] = { 49 | {"intersectionrect", geometry_intersectionrect}, 50 | {"rectmidpoint", geometry_rectmidpoint}, 51 | {NULL, NULL} 52 | }; 53 | 54 | int luaopen_mjolnir_geometry_internal(lua_State* L) { 55 | luaL_newlib(L, geometrylib); 56 | return 1; 57 | } 58 | -------------------------------------------------------------------------------- /mods/geometry/mjolnir.geometry-0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.geometry" 2 | version = "0.2-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to help with mathy stuff." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | ["mjolnir.geometry"] = "geometry.lua", 20 | ["mjolnir.geometry.internal"] = "geometry.m", 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /mods/hotkey/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/hotkey/hotkey.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.hotkey === 2 | --- 3 | --- Create and manage global hotkeys. 4 | 5 | local hotkey = require "mjolnir.hotkey.internal" 6 | local keycodes = require "mjolnir.keycodes" 7 | 8 | --- mjolnir.hotkey.new(mods, key, pressedfn, releasedfn = nil) -> hotkey 9 | --- Constructor 10 | --- Creates a new hotkey that can be enabled. 11 | --- 12 | --- The `mods` parameter is case-insensitive and may contain any of the following strings: "cmd", "ctrl", "alt", or "shift". 13 | --- 14 | --- The `key` parameter is case-insensitive and may be any string value found in mjolnir.keycodes.map 15 | --- 16 | --- The `pressedfn` parameter is the function that will be called when this hotkey is pressed. 17 | --- 18 | --- The `releasedfn` parameter is the function that will be called when this hotkey is released; this field is optional (i.e. may be nil or omitted). 19 | 20 | local function wrap(fn) 21 | return function() 22 | if fn then 23 | local ok, err = xpcall(fn, debug.traceback) 24 | if not ok then mjolnir.showerror(err) end 25 | end 26 | end 27 | end 28 | 29 | function hotkey.new(mods, key, pressedfn, releasedfn) 30 | local keycode 31 | 32 | if (key:sub(1, 1) == '#') then 33 | keycode = tonumber(key:sub(2)) 34 | else 35 | keycode = keycodes.map[key:lower()] 36 | end 37 | 38 | local _pressedfn = wrap(pressedfn) 39 | local _releasedfn = wrap(releasedfn) 40 | 41 | local k = hotkey._new(mods, keycode, _pressedfn, _releasedfn) 42 | return k 43 | end 44 | 45 | --- mjolnir.hotkey.bind(mods, key, pressedfn, releasedfn) -> hotkey 46 | --- Constructor 47 | --- Shortcut for: return mjolnir.hotkey.new(mods, key, pressedfn, releasedfn):enable() 48 | function hotkey.bind(...) 49 | return hotkey.new(...):enable() 50 | end 51 | 52 | return hotkey 53 | -------------------------------------------------------------------------------- /mods/hotkey/hotkey.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | static NSMutableIndexSet* handlers; 6 | 7 | static int store_hotkey(lua_State* L, int idx) { 8 | lua_pushvalue(L, idx); 9 | int x = luaL_ref(L, LUA_REGISTRYINDEX); 10 | [handlers addIndex: x]; 11 | return x; 12 | } 13 | 14 | static void remove_hotkey(lua_State* L, int x) { 15 | luaL_unref(L, LUA_REGISTRYINDEX, x); 16 | [handlers removeIndex: x]; 17 | } 18 | 19 | static void* push_hotkey(lua_State* L, int x) { 20 | lua_rawgeti(L, LUA_REGISTRYINDEX, x); 21 | return lua_touserdata(L, -1); 22 | } 23 | 24 | typedef struct _hotkey_t { 25 | UInt32 mods; 26 | UInt32 keycode; 27 | UInt32 uid; 28 | int pressedfn; 29 | int releasedfn; 30 | BOOL enabled; 31 | EventHotKeyRef carbonHotKey; 32 | } hotkey_t; 33 | 34 | 35 | static int hotkey_new(lua_State* L) { 36 | luaL_checktype(L, 1, LUA_TTABLE); 37 | UInt32 keycode = luaL_checknumber(L, 2); 38 | luaL_checktype(L, 3, LUA_TFUNCTION); 39 | luaL_checktype(L, 4, LUA_TFUNCTION); 40 | lua_settop(L, 4); 41 | 42 | hotkey_t* hotkey = lua_newuserdata(L, sizeof(hotkey_t)); 43 | memset(hotkey, 0, sizeof(hotkey_t)); 44 | 45 | hotkey->keycode = keycode; 46 | 47 | // use 'mjolnir.hotkey' metatable 48 | luaL_getmetatable(L, "mjolnir.hotkey"); 49 | lua_setmetatable(L, -2); 50 | 51 | // store pressedfn 52 | lua_pushvalue(L, 3); 53 | hotkey->pressedfn = luaL_ref(L, LUA_REGISTRYINDEX); 54 | 55 | // store releasedfn 56 | lua_pushvalue(L, 4); 57 | hotkey->releasedfn = luaL_ref(L, LUA_REGISTRYINDEX); 58 | 59 | // save mods 60 | lua_pushnil(L); 61 | while (lua_next(L, 1) != 0) { 62 | NSString* mod = [[NSString stringWithUTF8String:luaL_checkstring(L, -1)] lowercaseString]; 63 | if ([mod isEqualToString: @"cmd"]) hotkey->mods |= cmdKey; 64 | else if ([mod isEqualToString: @"ctrl"]) hotkey->mods |= controlKey; 65 | else if ([mod isEqualToString: @"alt"]) hotkey->mods |= optionKey; 66 | else if ([mod isEqualToString: @"shift"]) hotkey->mods |= shiftKey; 67 | lua_pop(L, 1); 68 | } 69 | 70 | return 1; 71 | } 72 | 73 | /// mjolnir.hotkey:enable() -> self 74 | /// Method 75 | /// Registers the hotkey's fn as the callback when the user presses key while holding mods. 76 | static int hotkey_enable(lua_State* L) { 77 | hotkey_t* hotkey = luaL_checkudata(L, 1, "mjolnir.hotkey"); 78 | lua_settop(L, 1); 79 | 80 | if (hotkey->enabled) 81 | return 1; 82 | 83 | hotkey->enabled = YES; 84 | hotkey->uid = store_hotkey(L, 1); 85 | EventHotKeyID hotKeyID = { .signature = 'MJLN', .id = hotkey->uid }; 86 | hotkey->carbonHotKey = NULL; 87 | RegisterEventHotKey(hotkey->keycode, hotkey->mods, hotKeyID, GetEventDispatcherTarget(), kEventHotKeyExclusive, &hotkey->carbonHotKey); 88 | 89 | lua_pushvalue(L, 1); 90 | return 1; 91 | } 92 | 93 | static void stop(lua_State* L, hotkey_t* hotkey) { 94 | if (!hotkey->enabled) 95 | return; 96 | 97 | hotkey->enabled = NO; 98 | remove_hotkey(L, hotkey->uid); 99 | UnregisterEventHotKey(hotkey->carbonHotKey); 100 | } 101 | 102 | /// mjolnir.hotkey:disable() -> self 103 | /// Method 104 | /// Disables the given hotkey; does not remove it from mjolnir.hotkey.keys. 105 | static int hotkey_disable(lua_State* L) { 106 | hotkey_t* hotkey = luaL_checkudata(L, 1, "mjolnir.hotkey"); 107 | stop(L, hotkey); 108 | lua_pushvalue(L, 1); 109 | return 1; 110 | } 111 | 112 | static int hotkey_gc(lua_State* L) { 113 | hotkey_t* hotkey = luaL_checkudata(L, 1, "mjolnir.hotkey"); 114 | stop(L, hotkey); 115 | luaL_unref(L, LUA_REGISTRYINDEX, hotkey->pressedfn); 116 | luaL_unref(L, LUA_REGISTRYINDEX, hotkey->releasedfn); 117 | return 0; 118 | } 119 | 120 | static const luaL_Reg hotkeylib[] = { 121 | {"_new", hotkey_new}, 122 | 123 | {"enable", hotkey_enable}, 124 | {"disable", hotkey_disable}, 125 | {"__gc", hotkey_gc}, 126 | 127 | {} 128 | }; 129 | 130 | static EventHandlerRef eventhandler; 131 | 132 | static OSStatus hotkey_callback(EventHandlerCallRef __attribute__ ((unused)) inHandlerCallRef, EventRef inEvent, void *inUserData) { 133 | EventHotKeyID eventID; 134 | GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(eventID), NULL, &eventID); 135 | 136 | lua_State* L = inUserData; 137 | 138 | hotkey_t* hotkey = push_hotkey(L, eventID.id); 139 | lua_pop(L, 1); 140 | 141 | int ref = (GetEventKind(inEvent) == kEventHotKeyPressed ? hotkey->pressedfn : hotkey->releasedfn); 142 | lua_rawgeti(L, LUA_REGISTRYINDEX, ref); 143 | lua_call(L, 0, 0); 144 | 145 | return noErr; 146 | } 147 | 148 | static int meta_gc(lua_State* L) { 149 | RemoveEventHandler(eventhandler); 150 | [handlers release]; 151 | return 0; 152 | } 153 | 154 | static const luaL_Reg metalib[] = { 155 | {"__gc", meta_gc}, 156 | {} 157 | }; 158 | 159 | int luaopen_mjolnir_hotkey_internal(lua_State* L) { 160 | handlers = [[NSMutableIndexSet indexSet] retain]; 161 | 162 | luaL_newlib(L, hotkeylib); 163 | 164 | // watch for hotkey events 165 | EventTypeSpec hotKeyPressedSpec[] = { 166 | {kEventClassKeyboard, kEventHotKeyPressed}, 167 | {kEventClassKeyboard, kEventHotKeyReleased}, 168 | }; 169 | InstallEventHandler(GetEventDispatcherTarget(), 170 | hotkey_callback, 171 | sizeof(hotKeyPressedSpec) / sizeof(EventTypeSpec), 172 | hotKeyPressedSpec, 173 | L, 174 | &eventhandler); 175 | 176 | // put hotkey in registry; necessary for luaL_checkudata() 177 | lua_pushvalue(L, -1); 178 | lua_setfield(L, LUA_REGISTRYINDEX, "mjolnir.hotkey"); 179 | 180 | // hotkey.__index = hotkey 181 | lua_pushvalue(L, -1); 182 | lua_setfield(L, -2, "__index"); 183 | 184 | // set metatable so gc function can cleanup module 185 | luaL_newlib(L, metalib); 186 | lua_setmetatable(L, -2); 187 | 188 | return 1; 189 | } 190 | -------------------------------------------------------------------------------- /mods/hotkey/mjolnir.hotkey-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.hotkey" 2 | version = "0.3-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to create and manage global hotkeys." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | "mjolnir.keycodes", 16 | } 17 | build = { 18 | type = "builtin", 19 | modules = { 20 | ["mjolnir.hotkey"] = "hotkey.lua", 21 | ["mjolnir.hotkey.internal"] = "hotkey.m", 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /mods/keycodes/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/keycodes/keycodes.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.keycodes === 2 | --- Functionality for converting between key-strings and key-codes. 3 | 4 | --- mjolnir.keycodes.map = {...} 5 | --- Variable 6 | --- A mapping from string representation of a key to its keycode, and vice versa. 7 | --- For example: keycodes[1] == "s", and keycodes["s"] == 1, and so on. 8 | --- This is primarily used by the mjolnir.eventtap and mjolnir.hotkey extensions. 9 | --- 10 | --- Valid strings are any single-character string, or any of the following strings: 11 | --- 12 | --- f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, 13 | --- f16, f17, f18, f19, f20, pad, pad*, pad+, pad/, pad-, pad=, 14 | --- pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7, pad8, pad9, 15 | --- padclear, padenter, return, tab, space, delete, escape, help, 16 | --- home, pageup, forwarddelete, end, pagedown, left, right, down, up 17 | 18 | local keycodes = require "mjolnir.keycodes.internal" 19 | keycodes.map = keycodes._cachemap() 20 | 21 | --- mjolnir.keycodes.inputsourcechanged(fn()) 22 | --- Function 23 | --- Sets the function to be called when your input source (i.e. qwerty, dvorak, colemac) changes. 24 | --- You can use this to rebind your hotkeys or whatever. 25 | --- Note: setting this will un-set functions previously registered by this function. 26 | function keycodes.inputsourcechanged(fn) 27 | if keycodes._callback then keycodes._callback:_stop() end 28 | keycodes._callback = keycodes._newcallback(function() 29 | keycodes.map = keycodes._cachemap() 30 | if fn then 31 | local ok, err = xpcall(fn, debug.traceback) 32 | if not ok then mjolnir.showerror(err) end 33 | end 34 | end) 35 | end 36 | 37 | keycodes.inputsourcechanged() 38 | 39 | return keycodes 40 | -------------------------------------------------------------------------------- /mods/keycodes/mjolnir.keycodes-0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.keycodes" 2 | version = "0.2-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to convert between key-strings and key-codes." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | ["mjolnir.keycodes"] = "keycodes.lua", 20 | ["mjolnir.keycodes.internal"] = "keycodes.m", 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /mods/screen/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /mods/screen/mjolnir.screen-0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "mjolnir.screen" 2 | version = "0.2-1" 3 | local url = "github.com/sdegutis/mjolnir-modules" 4 | local desc = "Mjolnir module to inspect and manipulate screens (i.e. monitors)." 5 | source = {url = "git://" .. url} 6 | description = { 7 | summary = desc, 8 | detailed = desc, 9 | homepage = "https://" .. url, 10 | license = "MIT", 11 | } 12 | supported_platforms = {"macosx"} 13 | dependencies = { 14 | "lua >= 5.2", 15 | "mjolnir.fnutils", 16 | "mjolnir.geometry", 17 | } 18 | build = { 19 | type = "builtin", 20 | modules = { 21 | ["mjolnir.screen"] = "screen.lua", 22 | ["mjolnir.screen.internal"] = "screen.m", 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /mods/screen/screen.lua: -------------------------------------------------------------------------------- 1 | --- === mjolnir.screen === 2 | --- 3 | --- Manipulate screens (i.e. monitors). 4 | --- 5 | --- You usually get a screen through a window (see `mjolnir.window.screen`). But you can get screens by themselves through this module, albeit not in any defined/useful order. 6 | --- 7 | --- Mjolnir's coordinate system assumes a grid that is the union of every screen's rect (see `mjolnir.screen.fullframe`). 8 | --- 9 | --- Every window's position (i.e. `topleft`) and size are relative to this grid, and they're usually within the grid. A window that's semi-offscreen only intersects the grid. 10 | 11 | local screen = require "mjolnir.screen.internal" 12 | local fnutils = require "mjolnir.fnutils" 13 | local geometry = require "mjolnir.geometry" 14 | 15 | --- mjolnir.screen:fullframe() -> rect 16 | --- Method 17 | --- Returns the screen's rect in absolute coordinates, including the dock and menu. 18 | function screen:fullframe() 19 | local primary_screen = screen.allscreens()[1] 20 | local f = self:_frame() 21 | f.y = primary_screen:_frame().h - f.h - f.y 22 | return f 23 | end 24 | 25 | --- mjolnir.screen:frame() -> rect 26 | --- Method 27 | --- Returns the screen's rect in absolute coordinates, without the dock or menu. 28 | function screen:frame() 29 | local primary_screen = screen.allscreens()[1] 30 | local f = self:_visibleframe() 31 | f.y = primary_screen:_frame().h - f.h - f.y 32 | return f 33 | end 34 | 35 | --- mjolnir.screen:next() -> screen 36 | --- Method 37 | --- Returns the screen 'after' this one (I have no idea how they're ordered though); this method wraps around to the first screen. 38 | function screen:next() 39 | local screens = screen.allscreens() 40 | local i = fnutils.indexof(screens, self) + 1 41 | if i > # screens then i = 1 end 42 | return screens[i] 43 | end 44 | 45 | --- mjolnir.screen:previous() -> screen 46 | --- Method 47 | --- Returns the screen 'before' this one (I have no idea how they're ordered though); this method wraps around to the last screen. 48 | function screen:previous() 49 | local screens = screen.allscreens() 50 | local i = fnutils.indexof(screens, self) - 1 51 | if i < 1 then i = # screens end 52 | return screens[i] 53 | end 54 | 55 | local function first_screen_in_direction(screen, numrotations) 56 | if #screen.allscreens() == 1 then 57 | return nil 58 | end 59 | 60 | -- assume looking to east 61 | 62 | -- use the score distance/cos(A/2), where A is the angle by which it 63 | -- differs from the straight line in the direction you're looking 64 | -- for. (may have to manually prevent division by zero.) 65 | 66 | -- thanks mark! 67 | 68 | local otherscreens = fnutils.filter(screen.allscreens(), function(s) return s ~= screen end) 69 | local startingpoint = geometry.rectmidpoint(screen:fullframe()) 70 | local closestscreens = {} 71 | 72 | for _, s in pairs(otherscreens) do 73 | local otherpoint = geometry.rectmidpoint(s:fullframe()) 74 | otherpoint = geometry.rotateccw(otherpoint, startingpoint, numrotations) 75 | 76 | local delta = { 77 | x = otherpoint.x - startingpoint.x, 78 | y = otherpoint.y - startingpoint.y, 79 | } 80 | 81 | if delta.x > 0 then 82 | local angle = math.atan2(delta.y, delta.x) 83 | local distance = geometry.hypot(delta) 84 | local anglediff = -angle 85 | local score = distance / math.cos(anglediff / 2) 86 | table.insert(closestscreens, {s = s, score = score}) 87 | end 88 | end 89 | 90 | table.sort(closestscreens, function(a, b) return a.score < b.score end) 91 | 92 | if #closestscreens > 0 then 93 | return closestscreens[1].s 94 | else 95 | return nil 96 | end 97 | end 98 | 99 | --- mjolnir.screen:toeast() 100 | --- Method 101 | --- Get the first screen to the east of this one, ordered by proximity. 102 | function screen:toeast() return first_screen_in_direction(self, 0) end 103 | 104 | --- mjolnir.screen:towest() 105 | --- Method 106 | --- Get the first screen to the west of this one, ordered by proximity. 107 | function screen:towest() return first_screen_in_direction(self, 2) end 108 | 109 | --- mjolnir.screen:tonorth() 110 | --- Method 111 | --- Get the first screen to the north of this one, ordered by proximity. 112 | function screen:tonorth() return first_screen_in_direction(self, 1) end 113 | 114 | --- mjolnir.screen:tosouth() 115 | --- Method 116 | --- Get the first screen to the south of this one, ordered by proximity. 117 | function screen:tosouth() return first_screen_in_direction(self, 3) end 118 | 119 | return screen 120 | -------------------------------------------------------------------------------- /mods/screen/screen.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #define get_screen_arg(L, idx) *((NSScreen**)luaL_checkudata(L, idx, "mjolnir.screen")) 6 | 7 | static void geom_pushrect(lua_State* L, NSRect rect) { 8 | lua_newtable(L); 9 | lua_pushnumber(L, rect.origin.x); lua_setfield(L, -2, "x"); 10 | lua_pushnumber(L, rect.origin.y); lua_setfield(L, -2, "y"); 11 | lua_pushnumber(L, rect.size.width); lua_setfield(L, -2, "w"); 12 | lua_pushnumber(L, rect.size.height); lua_setfield(L, -2, "h"); 13 | } 14 | 15 | static int screen_frame(lua_State* L) { 16 | NSScreen* screen = get_screen_arg(L, 1); 17 | geom_pushrect(L, [screen frame]); 18 | return 1; 19 | } 20 | 21 | static int screen_visibleframe(lua_State* L) { 22 | NSScreen* screen = get_screen_arg(L, 1); 23 | geom_pushrect(L, [screen visibleFrame]); 24 | return 1; 25 | } 26 | 27 | /// mjolnir.screen:id(screen) -> number 28 | /// Method 29 | /// Returns a screen's unique ID. 30 | static int screen_id(lua_State* L) { 31 | NSScreen* screen = get_screen_arg(L, 1); 32 | lua_pushnumber(L, [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] doubleValue]); 33 | return 1; 34 | } 35 | 36 | /// mjolnir.screen:name(screen) -> string 37 | /// Method 38 | /// Returns the preferred name for the screen set by the manufacturer. 39 | static int screen_name(lua_State* L) { 40 | NSScreen* screen = get_screen_arg(L, 1); 41 | CGDirectDisplayID screen_id = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue]; 42 | 43 | NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(screen_id), kIODisplayOnlyPreferredName); 44 | NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]]; 45 | 46 | if ([localizedNames count]) 47 | lua_pushstring(L, [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]); 48 | 49 | else 50 | lua_pushnil(L); 51 | 52 | return 1; 53 | } 54 | 55 | /// mjolnir.screen.settint(redarray, greenarray, bluearray) 56 | /// Function 57 | /// Set the tint on a screen; experimental. 58 | static int screen_settint(lua_State* L) { 59 | lua_len(L, 1); int red_len = lua_tonumber(L, -1); 60 | lua_len(L, 2); int green_len = lua_tonumber(L, -1); 61 | lua_len(L, 3); int blue_len = lua_tonumber(L, -1); 62 | 63 | CGGammaValue c_red[red_len]; 64 | CGGammaValue c_green[green_len]; 65 | CGGammaValue c_blue[blue_len]; 66 | 67 | lua_pushnil(L); 68 | while (lua_next(L, 1) != 0) { 69 | int i = lua_tonumber(L, -2) - 1; 70 | c_red[i] = lua_tonumber(L, -1); 71 | lua_pop(L, 1); 72 | } 73 | 74 | lua_pushnil(L); 75 | while (lua_next(L, 1) != 0) { 76 | int i = lua_tonumber(L, -2) - 1; 77 | c_green[i] = lua_tonumber(L, -1); 78 | lua_pop(L, 1); 79 | } 80 | 81 | lua_pushnil(L); 82 | while (lua_next(L, 1) != 0) { 83 | int i = lua_tonumber(L, -2) - 1; 84 | c_blue[i] = lua_tonumber(L, -1); 85 | lua_pop(L, 1); 86 | } 87 | 88 | CGSetDisplayTransferByTable(CGMainDisplayID(), red_len, c_red, c_green, c_blue); 89 | 90 | return 0; 91 | } 92 | 93 | static int screen_gc(lua_State* L) { 94 | NSScreen* screen = get_screen_arg(L, 1); 95 | [screen release]; 96 | return 0; 97 | } 98 | 99 | static int screen_eq(lua_State* L) { 100 | NSScreen* screenA = get_screen_arg(L, 1); 101 | NSScreen* screenB = get_screen_arg(L, 2); 102 | lua_pushboolean(L, [screenA isEqual: screenB]); 103 | return 1; 104 | } 105 | 106 | void new_screen(lua_State* L, NSScreen* screen) { 107 | NSScreen** screenptr = lua_newuserdata(L, sizeof(NSScreen**)); 108 | *screenptr = [screen retain]; 109 | 110 | luaL_getmetatable(L, "mjolnir.screen"); 111 | lua_setmetatable(L, -2); 112 | } 113 | 114 | /// mjolnir.screen.allscreens() -> screen[] 115 | /// Constructor 116 | /// Returns all the screens there are. 117 | static int screen_allscreens(lua_State* L) { 118 | lua_newtable(L); 119 | 120 | int i = 1; 121 | for (NSScreen* screen in [NSScreen screens]) { 122 | lua_pushnumber(L, i++); 123 | new_screen(L, screen); 124 | lua_settable(L, -3); 125 | } 126 | 127 | return 1; 128 | } 129 | 130 | /// mjolnir.screen.mainscreen() -> screen 131 | /// Constructor 132 | /// Returns the 'main' screen, i.e. the one containing the currently focused window. 133 | static int screen_mainscreen(lua_State* L) { 134 | new_screen(L, [NSScreen mainScreen]); 135 | return 1; 136 | } 137 | 138 | static const luaL_Reg screenlib[] = { 139 | {"allscreens", screen_allscreens}, 140 | {"mainscreen", screen_mainscreen}, 141 | {"settint", screen_settint}, 142 | 143 | {"_frame", screen_frame}, 144 | {"_visibleframe", screen_visibleframe}, 145 | {"id", screen_id}, 146 | {"name", screen_name}, 147 | 148 | {NULL, NULL} 149 | }; 150 | 151 | int luaopen_mjolnir_screen_internal(lua_State* L) { 152 | luaL_newlib(L, screenlib); 153 | 154 | if (luaL_newmetatable(L, "mjolnir.screen")) { 155 | lua_pushvalue(L, -2); 156 | lua_setfield(L, -2, "__index"); 157 | 158 | lua_pushcfunction(L, screen_gc); 159 | lua_setfield(L, -2, "__gc"); 160 | 161 | lua_pushcfunction(L, screen_eq); 162 | lua_setfield(L, -2, "__eq"); 163 | } 164 | lua_pop(L, 1); 165 | 166 | return 1; 167 | } 168 | -------------------------------------------------------------------------------- /sample-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | 20 | # LuaRocks 21 | *.o 22 | *.so 23 | *.rock 24 | -------------------------------------------------------------------------------- /sample-plugin/README.md: -------------------------------------------------------------------------------- 1 | This is a sample project to demonstrate writing a Mjolnir plugin. 2 | 3 | ### Your module's require-path 4 | 5 | Our sample module is called "mjolnir.yourid.foobar". This is both the 6 | name of the module, and its require-path. It's a good practice to make 7 | the module name and require path the same thing. 8 | 9 | ### Picking a name for your module 10 | 11 | You should prefix your module's name with "mjolnir." followed by a 12 | short unique identifier owned by you, e.g. maybe your initials. Don't 13 | use "yourid", that's just here for example. For example, my grid 14 | module is published as "mjolnir.sd.grid" where "sd" are my initials. 15 | 16 | ### Installing prerequisites 17 | 18 | Before you begin, you'll need to install Lua 5.2, LuaRocks, and 19 | MoonRocks. (If you have Mjolnir installed, you've probably already 20 | done the first two.) 21 | 22 | ~~~bash 23 | $ brew install homebrew/versions/lua52 24 | $ brew install luarocks --with-lua52 25 | $ luarocks install --server=http://rocks.moonscript.org moonrocks 26 | ~~~ 27 | 28 | ### A note about ARC 29 | 30 | If you're writing a module that contains any Objective-C, you'll 31 | probably have to write it without ARC. When LuaRocks compiles your 32 | module, it sets `CC="export MACOSX_DEPLOYMENT_TARGET=10.5; gcc"` for 33 | some reason, and it doesn't set the `-fobjc-arc` flag. You can try to 34 | change the build rules to fix these, but it's way more trouble than 35 | it's worth. It's easiest to do what I do and just skip using ARC. 36 | 37 | ### Optionally create an Xcode project 38 | 39 | If you're writing a module that has some C or Objective-C, you may 40 | want to create a little Xcode project for it. That way, you get 41 | autocompletion and other helpful Xcode features. 42 | 43 | 1. New Xcode Project -> Framework & Library -> C/C++ Library 44 | 2. Add `/usr/local/include` to "Header Search Paths" 45 | 3. Add `/usr/local/lib` to "Library Search Paths" 46 | 4. Add `-llua` to "Other Linker Flags" 47 | 5. Add your `.m` file to the Xcode project 48 | 6. Add `#import ` to the top of your `.m` file 49 | 7. Turn off ARC 50 | 51 | Keep in mind that this Xcode project has literally nothing to do with 52 | the actual binary that this will result in. LuaRocks takes care of 53 | that on its own, with its own build script. The Xcode project is 54 | purely here as a convenience. If you'd rather skip this whole step and 55 | write your Objective-C code in another editor, that works too. 56 | 57 | ### Building and testing your module 58 | 59 | LuaRocks has a helpful command to build and install the LuaRocks 60 | module in the current directory: 61 | 62 | ~~~bash 63 | $ luarocks make 64 | ~~~ 65 | 66 | Then, just launch Mjolnir, require your module, and test it out: 67 | 68 | ~~~lua 69 | local foobar = require "mjolnir.yourid.foobar" 70 | print(foobar.addnumbers(1, 2)) 71 | ~~~ 72 | 73 | You can repeat this process any number of times, since I'm pretty sure 74 | `luarocks make` will overwrite any pre-existing locally installed 75 | module with the same name. 76 | 77 | ### Publishing your module 78 | 79 | ~~~bash 80 | $ luarocks make 81 | ~~~ 82 | 83 | Now test it thoroughly. Make sure it actually works. Automated tests 84 | are not enough, actually load it up in Mjolnir and use it. Preferrably 85 | for a few days. 86 | 87 | Then, patch a MoonRocks file as specified below. 88 | 89 | You'll need to register an account at https://rocks.moonscript.org/ 90 | and create an API key in the Settings page for the next steps: 91 | 92 | ~~~bash 93 | $ luarocks pack mjolnir.yourid.foobar 94 | $ moonrocks upload --skip-pack mjolnir.yourid.foobar-0.1-1.rockspec 95 | $ moonrocks upload mjolnir.yourid.foobar-0.1-1.macosx-x86_64.rock 96 | ~~~ 97 | 98 | Congratulations, it's now available for everyone! 99 | 100 | ### Patching the MoonRocks file 101 | 102 | MoonRocks is almost entirely free of any Lua 5.1-specific 103 | features. All except two lines. 104 | 105 | So edit `/usr/local/share/lua/5.2/moonrocks/actions.lua`: 106 | 107 | Apply this pseudo-patch manually: 108 | 109 | ~~~lua 110 | - local fn, err = loadfile(fname) 111 | + local fn, err = loadfile(fname, nil, rockspec) 112 | 113 | - setfenv(fn, rockspec) 114 | ~~~ 115 | -------------------------------------------------------------------------------- /sample-plugin/foobar.lua: -------------------------------------------------------------------------------- 1 | local foobar = require "mjolnir.yourid.foobar.internal" 2 | -- If you don't have a C or Objective-C submodule, the above line gets simpler: 3 | -- local foobar = {} 4 | 5 | -- If your module depends on other Mjolnir modules, require them into locals like this: 6 | local application = require "mjolnir.application" 7 | 8 | -- Simple functions that can be defined in Lua, should be defined in Lua: 9 | function foobar.subtractnumbers(a, b) 10 | return a - b 11 | end 12 | 13 | -- Always return your top-level module; never set globals. 14 | return foobar 15 | -------------------------------------------------------------------------------- /sample-plugin/foobar.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | static int foobar_addnumbers(lua_State* L) { 6 | int a = luaL_checknumber(L, 1); 7 | int b = luaL_checknumber(L, 2); 8 | lua_pushnumber(L, a + b); 9 | return 1; 10 | } 11 | 12 | static const luaL_Reg foobarlib[] = { 13 | {"addnumbers", foobar_addnumbers}, 14 | 15 | {} // necessary sentinel 16 | }; 17 | 18 | 19 | /* NOTE: The substring "mjolnir_yourid_foobar_internal" in the following function's name 20 | must match the require-path of this file, i.e. "mjolnir.yourid.foobar.internal". */ 21 | 22 | int luaopen_mjolnir_yourid_foobar_internal(lua_State* L) { 23 | luaL_newlib(L, foobarlib); 24 | return 1; 25 | } 26 | -------------------------------------------------------------------------------- /sample-plugin/mjolnir.yourid.foobar-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- `package` is the require-path. 2 | -- 3 | -- Note: this must match the filename also. 4 | package = "mjolnir.yourid.foobar" 5 | 6 | -- `version` has two parts, your module's version (0.1) and the 7 | -- rockspec's version (1) in case you change metadata without 8 | -- changing the module's source code. 9 | -- 10 | -- Note: the version must match the version in the filename. 11 | version = "0.1-1" 12 | 13 | -- General metadata: 14 | 15 | local url = "github.com/yourname/mjolnir.yourid.foobar" 16 | local desc = "Mjolnir module to add and subtract numbers." 17 | 18 | source = {url = "git://" .. url} 19 | description = { 20 | summary = desc, 21 | detailed = desc, 22 | homepage = "https://" .. url, 23 | license = "MIT", 24 | } 25 | 26 | -- Dependencies: 27 | 28 | supported_platforms = {"macosx"} 29 | dependencies = { 30 | "lua >= 5.2", 31 | -- You can add Mjolnir core modules as dependencies, 32 | -- i.e. "mjolnir.application", "mjolnir.hotkey", whatever. 33 | -- 34 | -- For example, if your module depends on `mjolnir.fnutils`, 35 | -- uncomment the following line: 36 | -- 37 | -- "mjolnir.fnutils", 38 | } 39 | 40 | -- Build rules: 41 | 42 | build = { 43 | type = "builtin", 44 | modules = { 45 | -- This is the top-level module: 46 | ["mjolnir.yourid.foobar"] = "foobar.lua", 47 | 48 | -- If you have an internal C or Objective-C submodule, include it here: 49 | ["mjolnir.yourid.foobar.internal"] = "foobar.m", 50 | 51 | -- Note: the key on the left side is the require-path; the value 52 | -- on the right is the filename relative to the current dir. 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /screenshots/dict.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/screenshots/dict.gif -------------------------------------------------------------------------------- /screenshots/grid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjolnirapp/mjolnir/1c862deb31742d4b2dc593b74c29a24b33917254/screenshots/grid.gif --------------------------------------------------------------------------------