├── Packages ├── SourcePawn │ ├── .extracted-sublime-package │ ├── .gitattributes │ ├── .gitignore │ ├── CFG.sublime-settings │ ├── CFG.sublime-syntax │ ├── COPYING │ ├── Comments.tmPreferences │ ├── CompletionRules.tmPreferences │ ├── Main.sublime-menu │ ├── README.md │ ├── SPCompletions.py │ ├── SourcePawn Completions.sublime-settings │ ├── SourcePawn.sublime-build.example │ ├── SourcePawn.sublime-completions │ ├── SourcePawn.sublime-settings │ ├── SourcePawn.sublime-syntax │ ├── SourcePawnSnippets │ │ ├── AmbientSHook.sublime-snippet │ │ ├── Case.sublime-snippet │ │ ├── CommandListener.sublime-snippet │ │ ├── ConCmd.sublime-snippet │ │ ├── ConVarQueryFinished01.sublime-snippet │ │ ├── ConVarQueryFinished02.sublime-snippet │ │ ├── ConvarChanged.sublime-snippet │ │ ├── CookieMenuHandler.sublime-snippet │ │ ├── DHookCallback01.sublime-snippet │ │ ├── DHookCallback02.sublime-snippet │ │ ├── DHookCallback03.sublime-snippet │ │ ├── DHookCallback04.sublime-snippet │ │ ├── DHookCallback05.sublime-snippet │ │ ├── DHookCallback06.sublime-snippet │ │ ├── DHookCallback07.sublime-snippet │ │ ├── DHookCallback08.sublime-snippet │ │ ├── DHookCallback09.sublime-snippet │ │ ├── DHookCallback10.sublime-snippet │ │ ├── DHookCallback11.sublime-snippet │ │ ├── DHookCallback12.sublime-snippet │ │ ├── DHookRemovalCB.sublime-snippet │ │ ├── Default.sublime-snippet │ │ ├── Do.sublime-snippet │ │ ├── Else.sublime-snippet │ │ ├── EntityOutput01.sublime-snippet │ │ ├── EntityOutput02.sublime-snippet │ │ ├── EventHook01.sublime-snippet │ │ ├── EventHook02.sublime-snippet │ │ ├── For.sublime-snippet │ │ ├── GameLogHook.sublime-snippet │ │ ├── If.sublime-snippet │ │ ├── Include.sublime-snippet │ │ ├── ListenCB01.sublime-snippet │ │ ├── ListenCB02.sublime-snippet │ │ ├── MenuHandler.sublime-snippet │ │ ├── Methodmap.sublime-snippet │ │ ├── MsgHook01.sublime-snippet │ │ ├── MsgHook02.sublime-snippet │ │ ├── MsgPostHook.sublime-snippet │ │ ├── MultiTargetFilter01.sublime-snippet │ │ ├── MultiTargetFilter02.sublime-snippet │ │ ├── MultiTargetFilter03.sublime-snippet │ │ ├── MultiTargetFilter04.sublime-snippet │ │ ├── MyInfo.sublime-snippet │ │ ├── NativeCall01.sublime-snippet │ │ ├── NativeCall02.sublime-snippet │ │ ├── NewPlugin.sublime-snippet │ │ ├── NormalSHook.sublime-snippet │ │ ├── RequestFrameCallback01.sublime-snippet │ │ ├── RequestFrameCallback02.sublime-snippet │ │ ├── SDKHookCB01.sublime-snippet │ │ ├── SDKHookCB02.sublime-snippet │ │ ├── SDKHookCB03.sublime-snippet │ │ ├── SDKHookCB04.sublime-snippet │ │ ├── SDKHookCB05.sublime-snippet │ │ ├── SDKHookCB06.sublime-snippet │ │ ├── SDKHookCB07.sublime-snippet │ │ ├── SDKHookCB08.sublime-snippet │ │ ├── SDKHookCB09.sublime-snippet │ │ ├── SDKHookCB10.sublime-snippet │ │ ├── SDKHookCB11.sublime-snippet │ │ ├── SDKHookCB12.sublime-snippet │ │ ├── SDKHookCB13.sublime-snippet │ │ ├── SDKHookCB14.sublime-snippet │ │ ├── SDKHookCB15.sublime-snippet │ │ ├── SDKHookCB16.sublime-snippet │ │ ├── SDKHookCB17.sublime-snippet │ │ ├── SDKHookCB18.sublime-snippet │ │ ├── SDKHookCB19.sublime-snippet │ │ ├── SDKHookCB20.sublime-snippet │ │ ├── SDKHookCB21.sublime-snippet │ │ ├── SDKHookCB22.sublime-snippet │ │ ├── SDKHookCB23.sublime-snippet │ │ ├── SDKHookCB24.sublime-snippet │ │ ├── SMC_EndSection.sublime-snippet │ │ ├── SMC_KeyValue.sublime-snippet │ │ ├── SMC_NewSection.sublime-snippet │ │ ├── SMC_ParseEnd.sublime-snippet │ │ ├── SMC_ParseStart.sublime-snippet │ │ ├── SMC_RawLine.sublime-snippet │ │ ├── SQLConnectCallback.sublime-snippet │ │ ├── SQLQueryCallback.sublime-snippet │ │ ├── SQLTCallback.sublime-snippet │ │ ├── SQLTxnFailure.sublime-snippet │ │ ├── SQLTxnSuccess.sublime-snippet │ │ ├── SortFunc1D.sublime-snippet │ │ ├── SortFunc2D.sublime-snippet │ │ ├── SortFuncADTArray.sublime-snippet │ │ ├── SrvCmd.sublime-snippet │ │ ├── Switch.sublime-snippet │ │ ├── TEHook.sublime-snippet │ │ ├── TestPlugin.sublime-snippet │ │ ├── Timer01.sublime-snippet │ │ ├── Timer02.sublime-snippet │ │ ├── TopMenuHandler.sublime-snippet │ │ ├── TraceEntityEnumerator01.sublime-snippet │ │ ├── TraceEntityEnumerator02.sublime-snippet │ │ ├── TraceEntityFilter01.sublime-snippet │ │ ├── TraceEntityFilter02.sublime-snippet │ │ ├── Typedef.sublime-snippet │ │ ├── Typeset.sublime-snippet │ │ ├── ViewAs.sublime-snippet │ │ ├── VoteHandler.sublime-snippet │ │ └── While.sublime-snippet │ ├── SymbolList.tmPreferences │ ├── misc │ │ └── constantcrawler.py │ ├── notes.txt │ ├── pathtools │ │ ├── __init__.py │ │ ├── path.py │ │ ├── patterns.py │ │ └── version.py │ └── watchdog │ │ ├── __init__.py │ │ ├── events.py │ │ ├── observers │ │ ├── __init__.py │ │ ├── api.py │ │ ├── fsevents.py │ │ ├── fsevents2.py │ │ ├── inotify.py │ │ ├── inotify_buffer.py │ │ ├── inotify_c.py │ │ ├── kqueue.py │ │ ├── polling.py │ │ ├── read_directory_changes.py │ │ └── winapi.py │ │ ├── tricks │ │ └── __init__.py │ │ ├── utils │ │ ├── __init__.py │ │ ├── bricks.py │ │ ├── compat.py │ │ ├── decorators.py │ │ ├── dirsnapshot.py │ │ ├── echo.py │ │ ├── importlib2.py │ │ ├── platform.py │ │ ├── unicode_paths.py │ │ └── win32stat.py │ │ └── version.py └── User │ ├── Preferences.sublime-settings │ ├── SaucePawn.sublime-color-scheme │ ├── SourcePawn Completions.sublime-settings │ └── bh_core.sublime-settings └── README.md /Packages/SourcePawn/.extracted-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoinedSenses/sourcepawn_sublime_stuff/aec6d237c125fa6b38ec3f2b9e062d72457553b9/Packages/SourcePawn/.extracted-sublime-package -------------------------------------------------------------------------------- /Packages/SourcePawn/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.sublime-* text 7 | *.*Theme text 8 | *.*Preferences text 9 | *.*Language text -------------------------------------------------------------------------------- /Packages/SourcePawn/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.cache 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Packages/SourcePawn/CFG.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": 3 | [ 4 | "cfg" 5 | ] 6 | } -------------------------------------------------------------------------------- /Packages/SourcePawn/CFG.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | name: Config 4 | file_extensions: [cfg] 5 | scope: source.cfg 6 | 7 | variables: 8 | end_of_line: '(? 2 | 3 | 4 | 5 | name 6 | SourcePawnComments 7 | scope 8 | source.sp 9 | settings 10 | 11 | shellVariables 12 | 13 | 14 | name 15 | TM_COMMENT_START 16 | value 17 | // 18 | 19 | 20 | name 21 | TM_COMMENT_START_2 22 | value 23 | /* 24 | 25 | 26 | name 27 | TM_COMMENT_END_2 28 | value 29 | */ 30 | 31 | 32 | name 33 | TM_COMMENT_DISABLE_INDENT 34 | value 35 | yes 36 | 37 | 38 | name 39 | TM_COMMENT_DISABLE_INDENT_2 40 | value 41 | yes 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Packages/SourcePawn/CompletionRules.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope 5 | source.sp 6 | settings 7 | 8 | cancelCompletion 9 | 10 | ^\s*(#if|#else|#elseif|#endif|#pragma) 11 | 12 | 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "SourcePawn Completions", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/SourcePawn Completions/SourcePawn Completions.sublime-settings"}, 21 | "caption": "Settings - Default" 22 | }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/SourcePawn Completions.sublime-settings"}, 26 | "caption": "Settings - User" 27 | }, 28 | { "caption": "-" }, 29 | { 30 | "command": "open_file", 31 | "args": {"file": "${packages}/SourcePawn Completions/SourcePawn.sublime-build.example"}, 32 | "caption": "Build system - Example" 33 | }, 34 | { 35 | "command": "open_file", 36 | "args": {"file": "${packages}/User/SourcePawn.sublime-build"}, 37 | "caption": "Build system - User" 38 | }, 39 | { "caption": "-" } 40 | ] 41 | } 42 | ] 43 | } 44 | ] 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /Packages/SourcePawn/README.md: -------------------------------------------------------------------------------- 1 | # SourcePawn Completions for SublimeText 3 2 | 3 | A Sublime Text 4 plugin that dynamically genenerates completions for SourcePawn. 4 | 5 | Based on [sublime-sourcepawn](https://github.com/austinwagner/sublime-sourcepawn). 6 | Includes [watchdog python module](https://https://github.com/gorakhargosh/watchdog) 7 | 8 | 9 |

10 | 11 | ## Installing 12 | 13 | ### Via [package control](https://packagecontrol.io/installation) 14 | 15 | ~~1. Press `Control+Shift+P` or `Cmd+Shift+P` (on Mac)~~ 16 | ~~2. Type **Package Control: Install Package**, hit enter.~~ 17 | ~~3. Type in **SourcePawn Completions**, hit enter again.~~ 18 | 19 | ### Manually 20 | 21 | Clone this repository into a subfolder of your Packages directory: 22 | * Mac OS `~/Library/Application Support/Sublime Text 3/Packages/` 23 | * Windows `%APPDATA%/Sublime Text 3/Packages/` 24 | 25 | ## Configuration 26 | **Note:** All paths must be an absolute. Relative paths are unsupported. 27 | 28 | 1. Open *Sublime Text* -> *Preferences* -> *Package Settings* -> *SourcePawn Completions* -> *Settings - User*. 29 | 2. Add `include_directory` setting with path to your SourceMod include files (`sourcemod/scripting` folder). (You could look for some exmaples in *Settings - Default*) 30 | 3. Save and close file. 31 | 4. Open *Sublime Text* -> *Preferences* -> *Package Settings* -> *SourcePawn Completions* -> *Build settings - Example* and *Build settings - User* 32 | 5. Copy one of `cmd` settings from `SourcePawn.sublime-build.example`, paste it to `SourcePawn.sublime-build` and ajust path to `spcomp`. This allows you to use **Build** feature in SublimeText. 33 | 6. Save and close file. 34 | 35 | ## Usage 36 | 37 | SourcePawn Completions is automatically active on .sp and .inc files. The completion list updates whenever you stop typing for 1 second or when you save the file. 38 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawn Completions.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // path to sourcemod "scripting/include" folder 3 | // Windows example: // Support for multiple directories. Searches top to bottom until it finds include 4 | // "include_directory": [ 5 | // "D:\\sourcemod\\scripting\\include", 6 | // "C:\\another\\sourcemod\\include", // optional 7 | /// "etc . . ." // optional 8 | // ], 9 | // OSX example: 10 | // "include_directory": [ 11 | // "/Users/ppalex/sourcemod/scripting/include", 12 | // "/Users/ppalex/some/other/sourcemod/scripting/include", // optional 13 | // "etc . . ." // optional 14 | // ], 15 | 16 | // delay (in seconds) before regenerating auto-completion snippets 17 | "live_refresh_delay": 1.0 18 | } 19 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawn.sublime-build.example: -------------------------------------------------------------------------------- 1 | { 2 | // Copy on of "cmd" examples to "Build settings - User" 3 | // and ajust path to spcomp to make build-system work. 4 | 5 | // For default sourcemod scripting directory : 6 | // "cmd": ["", "-o$file_path/../plugins/$file_name", "$file"], 7 | 8 | // For custom sourcemod scripting directory : 9 | // "cmd": ["", "-i", "-o$file_path/$file_base_name.smx", "$file"], 10 | 11 | // Windows example: 12 | "cmd": ["X:/somefolder/spcomp", "-iX:/somefolder/scripting/include", "-o$file_path/$file_base_name.smx", "$file"], 13 | "cmd": ["X:/game/csgo/addons/sourcemod/scripting/spcomp", "-o$file_path/../plugins/$file_name", "$file"], 14 | 15 | // Linux example: 16 | "cmd": ["/home/User/sm/spcomp", "-i/home/User/sm/include", "-o$file_path/$file_base_name.smx", "$file"], 17 | "cmd": ["/home/User/game/csgo/addons/sourcemod/scripting/spcomp", "-o$file_path/../plugins/$file_name", "$file"], 18 | 19 | // OSX example: 20 | "cmd": ["/Users/ppalex/sourcemod/scripting/spcomp", "-i$file_path/include", "-o$file_path/../plugins/$file_name", "$file"], 21 | 22 | "file_regex": "(.*)\\((\\d+)\\) : ()(.*$)", 23 | "selector": "source.sp" 24 | } 25 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawn.sublime-completions: -------------------------------------------------------------------------------- 1 | { 2 | "scope": "source.sp", 3 | "completions": 4 | [ 5 | { "trigger": "view_as", "contents": "view_as<$1>($0)" } 6 | ] 7 | } -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawn.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": 3 | [ 4 | "sp", 5 | "inc" 6 | ], 7 | 8 | // "word_separators": "./\\()\"':,;<>~!@#$%^&*|+=[]{}`~?", 9 | "smart_indent": true, 10 | "detect_indentation": false, 11 | "tab_size": 4, 12 | "translate_tabs_to_spaces": false, 13 | "draw_indent_guides": false, 14 | 15 | "auto_complete_include_snippets": "true", 16 | "auto_complete_preserve_order":"none", 17 | "auto_complete_selector": "source - comment - string.quoted", 18 | } 19 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/AmbientSHook.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | __AmbientSHook(char[PLATFORM_MAX_PATH], int&, float&, int&, int&, float[3], int&, float&) : Action 12 | 13 | source.sp - meta.function 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Case.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | case 9 | 10 | source.sp & meta.function & meta.block 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/CommandListener.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __CommandListener(int, const char[], int) : Action 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ConCmd.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | __ConCmd(int, int) : Action 9 | source.sp - meta.function 10 | 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ConVarQueryFinished01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __ConVarQueryFinished(QueryCookie, int, ConVarQueryResult, const char[], const char[]) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ConVarQueryFinished02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __ConVarQueryFinished(QueryCookie, int, ConVarQueryResult, const char[], const char[], any)) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ConvarChanged.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __ConVarChanged(ConVar, const char[], const char[]) : void 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/CookieMenuHandler.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __CookieMenuHandler(int, CookieMenuAction, any, char[], int) : void 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback() : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(int) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback03.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback04.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(int, DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback05.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(DHookReturn) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback06.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(int, DHookReturn) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback07.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(DHookReturn, DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback08.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(int, DHookReturn, DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback09.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(Address) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback10.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(Address, DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback11.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(Address, DHookReturn) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookCallback12.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __DHookCallback(Address, DHookReturn, DHookParam) : MRESReturn 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/DHookRemovalCB.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __DHookRemovalCB(int) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Default.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | default 9 | 10 | source.sp & meta.function & meta.block 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Do.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | do 9 | 10 | source.sp & meta.function & meta.block 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Else.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | else 8 | source.sp & meta.function & meta.block 9 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/EntityOutput01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __EntityOutput(const char[], int, int, float) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/EntityOutput02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __EntityOutput(const char[], int, int, float) : Action 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/EventHook01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __EventHook(Event, const char[], bool) : void 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/EventHook02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __EventHook(Event, const char[], bool) : Action 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/For.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | for 8 | source.sp & meta.function & meta.block 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/GameLogHook.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __GameLogHook(const char[]) : Action 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/If.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 6 | if 7 | source.sp & meta.function & meta.block 8 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Include.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 48 | __include 49 | source.sp - meta.function 50 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ListenCB01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __ListenCB(int) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ListenCB02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __ListenCB(int, const char[]) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MenuHandler.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 57 | 58 | __MenuHandler(Menu, MenuAction, int, int) : int 59 | 60 | source.sp - meta.function 61 | 62 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Methodmap.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | ($0); 6 | } 7 | } 8 | ]]> 9 | methodmap 10 | source.sp - meta.function 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MsgHook01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MsgHook(UserMsg, BfRead, const int[], int, bool, bool) : Action 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MsgHook02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MsgHook(UserMsg, Protobuf, const int[], int, bool, bool) : Action 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MsgPostHook.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __MsgPostHook(UserMsg, bool) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MultiTargetFilter01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MultiTargetFilter(const char[], Handle) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MultiTargetFilter02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MultiTargetFilter(const char[], ArrayList) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MultiTargetFilter03.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MultiTargetFilter(const char[], Handle, int) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MultiTargetFilter04.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __MultiTargetFilter(const char[], ArrayList, int) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/MyInfo.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 11 | __myinfo 12 | source.sp - meta.function 13 | 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/NativeCall01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __NativeCall(Handle, int) : int 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/NativeCall02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __NativeCall(Handle, int) : any 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/NewPlugin.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | #define PLUGIN_NAME "${1:NewPlugin}" 9 | #define PLUGIN_AUTHOR "${2:}" 10 | #define PLUGIN_DESCRIPTION "${3:}" 11 | #define PLUGIN_VERSION "${4:0.1.0}" 12 | #define PLUGIN_URL "${5:https://alliedmods.net}" 13 | 14 | public Plugin myinfo = { 15 | name = PLUGIN_NAME, 16 | author = PLUGIN_AUTHOR, 17 | description = PLUGIN_DESCRIPTION, 18 | version = PLUGIN_VERSION, 19 | url = PLUGIN_URL 20 | } 21 | 22 | public void OnPluginStart() { 23 | CreateConVar( 24 | "sm_${1/([A-Z])|(\s)/(?1\l$1:)(?2:)/g}_version", 25 | PLUGIN_VERSION, 26 | PLUGIN_DESCRIPTION, 27 | FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD 28 | ).SetString(PLUGIN_VERSION); 29 | 30 | $0 31 | } 32 | ]]> 33 | __newplugin 34 | source.sp - meta.function 35 | 36 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/NormalSHook.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | __NormalSHook(int[MAXPLAYERS], int&, char[PLATFORM_MAX_PATH], int&, int&, float&, int&, int&, int&, char[PLATFORM_MAX_PATH], int&) : Action 12 | 13 | source.sp - meta.function 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/RequestFrameCallback01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __RequestFrameCallback() : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/RequestFrameCallback02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __RequestFrameCallback(any) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int) : void 9 | 10 | source.sp - meta.function 11 | PreThink/Post PostThink/Post 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int) : Action 11 | 12 | source.sp - meta.function 13 | Spawn Think 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB03.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int) : void 9 | 10 | source.sp - meta.function 11 | GroundEntChanged SpawnPost ThinkPost VPhysicsUpdate/Post 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB04.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int) : Action 11 | 12 | source.sp - meta.function 13 | EndTouch StartTouch Touch Blocked 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB05.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int) : void 9 | 10 | source.sp - meta.function 11 | EndTouchPost StartTouchPost TouchPost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB06.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int) : Action 11 | 12 | source.sp - meta.function 13 | SetTransmit 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB07.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int) : Action 11 | 12 | source.sp - meta.function 13 | WeaponCanSwitchTo WeaponCanUse WeaponDrop WeaponEquip WeaponSwitch 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB08.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int) : void 9 | 10 | source.sp - meta.function 11 | WeaponCanSwitchToPost WeaponCanUsePost WeaponDropPost WeaponEquipPost WeaponSwitchPost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB09.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int&) : Action 11 | 12 | source.sp - meta.function 13 | GetMaxHealth 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB10.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int&, int&, float&, int&) : Action 11 | 12 | source.sp - meta.function 13 | OnTakeDamage OnTakeDamageAlive 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB11.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int&, int&, float&, int&, int&, float[3], float[3]) : Action 11 | 12 | source.sp - meta.function 13 | OnTakeDamage OnTakeDamageAlive 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB12.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | __SDKHookCB(int, int&, int&, float&, int&, int&, float[3], float[3], int) : Action 12 | 13 | source.sp - meta.function 14 | OnTakeDamage OnTakeDamageAlive 15 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB13.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int, int, float, int) : void 9 | 10 | source.sp - meta.function 11 | OnTakeDamagePost OnTakeDamageAlivePost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB14.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int, int, float, int, int, const float[3], const float[3]) : void 9 | 10 | source.sp - meta.function 11 | OnTakeDamagePost OnTakeDamageAlivePost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB15.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | __SDKHookCB(int, int, int, float, int, int, const float[3], const float[3], int) : void 10 | 11 | source.sp - meta.function 12 | OnTakeDamagePost OnTakeDamageAlivePost 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB16.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int, const char[]) : void 9 | 10 | source.sp - meta.function 11 | FireBulletsPost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB17.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int&, int&, float&, int&, int&, int, int) : Action 11 | 12 | source.sp - meta.function 13 | TraceAttack 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB18.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int, int, float, int, int, int, int) : void 9 | 10 | source.sp - meta.function 11 | TraceAttackPost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB19.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int, int, bool) : bool 11 | 12 | source.sp - meta.function 13 | ShouldCollide 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB20.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, int, int, UseType, float) : Action 11 | 12 | source.sp - meta.function 13 | Use 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB21.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, int, int, UseType, float) : void 9 | 10 | source.sp - meta.function 11 | UsePost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB22.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int) : Action 11 | 12 | source.sp - meta.function 13 | Reload 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB23.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SDKHookCB(int, bool)) : void 9 | 10 | source.sp - meta.function 11 | ReloadPost 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SDKHookCB24.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SDKHookCB(int, bool) : bool 11 | 12 | source.sp - meta.function 13 | CanBeAutobalanced 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_EndSection.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SMC_EndSection(SMCParser) : SMCResult 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_KeyValue.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SMC_KeyValue(SMCParser, const char[], const char[], bool, bool) : SMCResult 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_NewSection.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SMC_NewSection(SMCParser, const char[], bool) : SMCResult 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_ParseEnd.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SMC_ParseEnd(SMCParser, bool, bool) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_ParseStart.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SMC_ParseStart(SMCParser) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SMC_RawLine.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SMC_RawLine(SMCParser, const char[], int) : SMCResult 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SQLConnectCallback.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 11 | __SQLConnectCallback(Database, const char[], any) : void 12 | source.sp - meta.function 13 | 14 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SQLQueryCallback.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 12 | __SQLQueryCallback(Database, DBResultSet, const char[], any) : void 13 | source.sp - meta.function 14 | 15 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SQLTCallback.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | __SQLTCallback(Handle, Handle, const char[], any) : void 9 | 10 | source.sp - meta.function 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SQLTxnFailure.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __SQLTxnFailure(Database, any, int, const char[], int failIndex, any[]) : void 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SQLTxnSuccess.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | __SQLTxnSuccess(Database, any, int, DBResultSet[], any[]) : void 8 | source.sp - meta.function 9 | 10 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SortFunc1D.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SortFunc1D(any, any, const any[], any) : int 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SortFunc2D.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SortFunc2D(any[], any[], const any[][], any) : int 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SortFuncADTArray.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __SortFuncADTArray(int, int, Handle, any) : int 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/SrvCmd.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | __SrvCmd(int) : Action 10 | source.sp - meta.function 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Switch.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | switch 9 | 10 | source.sp & meta.function & meta.block 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TEHook.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __TEHook(const char[], const int[], int, float) : Action 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TestPlugin.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | public Plugin myinfo = { 9 | name = "${TM_FILENAME/(.+)\..+/$1/}", 10 | author = "", 11 | description = "", 12 | version = "0.1.0", 13 | url = "" 14 | } 15 | 16 | public void OnPluginStart() { 17 | RegAdminCmd("sm_${1:test}", ${2:cmdTest}, ADMFLAG_ROOT); 18 | } 19 | 20 | public Action $2(int client, int args) { 21 | $0 22 | 23 | return Plugin_Handled; 24 | } 25 | ]]> 26 | __test 27 | source.sp - meta.function 28 | 29 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Timer01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | __Timer(Handle) : Action 9 | source.sp - meta.function 10 | 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Timer02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | __Timer(Handle, any) : Action 9 | source.sp - meta.function 10 | 11 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TopMenuHandler.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | __TopMenuHandler(TopMenu, TopMenuAction, TopMenuObject, int, char[], int) : void 10 | 11 | source.sp - meta.function 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TraceEntityEnumerator01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __TraceEntityEnumerator(int) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TraceEntityEnumerator02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __TraceEntityEnumerator(int, any) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TraceEntityFilter01.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __TraceEntityFilter(int, int) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/TraceEntityFilter02.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | __TraceEntityFilter(int, int, any) : bool 11 | 12 | source.sp - meta.function 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Typedef.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | typedef 6 | source.sp - meta.function 7 | 8 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/Typeset.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | typeset 10 | 11 | source.sp - meta.function 12 | 13 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/ViewAs.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | ($2) 4 | ]]> 5 | view_as 6 | source.sp 7 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/VoteHandler.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | __VoteHandler(Menu, int, int, const int[][], int, const int[][]) : void 10 | 11 | source.sp - meta.function 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SourcePawnSnippets/While.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | while 9 | 10 | source.sp & meta.function & meta.block 11 | 12 | -------------------------------------------------------------------------------- /Packages/SourcePawn/SymbolList.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | name 5 | Symbol List 6 | scope 7 | 8 | settings 9 | 10 | showInSymbolList 11 | 1 12 | showInIndexedSymbolList 13 | 1 14 | 15 | 16 | -------------------------------------------------------------------------------- /Packages/SourcePawn/misc/constantcrawler.py: -------------------------------------------------------------------------------- 1 | from os import PathLike 2 | from pathlib import PurePath 3 | import os.path 4 | import pathlib 5 | import pyperclip 6 | import re 7 | import sys 8 | from argparse import ArgumentParser 9 | from io import TextIOWrapper 10 | from trieregex import TrieRegEx # https://github.com/ermanh/trieregex 11 | 12 | 13 | argparser = ArgumentParser(description='Crawls through include directories and files to generate a regex trie for matching constants') 14 | argparser.add_argument('--debug', help='Enable debug messages', action='store_true') 15 | argparser.add_argument('--recursive', help='Enable recusive directory crawling', action='store_true') 16 | argparser.add_argument('paths', metavar='Paths', type=str, nargs='+', help='Paths to crawl. Can be directory or file.') 17 | argparser.add_argument_group() 18 | 19 | parsedargs = argparser.parse_args() 20 | 21 | 22 | class Debug: 23 | __enabled = parsedargs.debug 24 | 25 | @staticmethod 26 | def log(value: str) -> None: 27 | if Debug.__enabled: print(value) 28 | 29 | 30 | def main(args: list[str]): 31 | """ 32 | Crawls through include directories and files to generate a regex trie for matching constants. 33 | Ignores variables IN_ALL_CAPS since those are already discovered with a basic all-caps regex for the 34 | purpose of syntax highlighting. 35 | 36 | Args: 37 | args (list[str]): List of paths to process 38 | """ 39 | if len(args) < 1: 40 | argparser.print_help() 41 | sys.exit(1) 42 | 43 | error: str = '' 44 | for arg in args: 45 | if not os.path.exists(arg): 46 | error += '\n Path not found: {}'.format(arg) 47 | if error: 48 | print('\nErrors detected:{}'.format(error)) 49 | sys.exit(1) 50 | 51 | trie: TrieRegEx = TrieRegEx() 52 | 53 | # loop through all args and attempt to parse 54 | for arg in args: 55 | # if arg is file and ends with .inc, then parse it 56 | if os.path.isfile(arg): 57 | if args.endswith('.inc'): 58 | with open(arg) as f: parse_file(f, trie) 59 | elif os.path.isdir(arg): 60 | parse_directory(PurePath(arg), parsedargs.recursive, trie) 61 | 62 | result: str = trie.regex() 63 | Debug.log('-- Result: --\n{}'.format(result)) 64 | 65 | if result: 66 | pyperclip.copy(result) 67 | print('Output copied to clipboard (Len: {})'.format(len(result))) 68 | else: 69 | print('No results') 70 | 71 | 72 | def parse_directory(dir: PathLike, recursive: bool, trie: TrieRegEx) -> None: 73 | """ 74 | Attempts to parse files within the given directory 75 | 76 | Args: 77 | dir (str): The directory to crawl through 78 | recursive (bool): If true, crawls through all subdirectories 79 | trie (TrieRegEx): The trie to add results to. 80 | """ 81 | if recursive: 82 | for path, _, files in os.walk(dir): 83 | for name in files: 84 | if name.endswith('.inc'): 85 | with open(os.path.join(path, name)) as f: parse_file(f, trie) 86 | else: 87 | # loop through each file in the directory 88 | for file_name in os.listdir(dir): 89 | # if it's not a .inc file, skip it 90 | if not file_name.endswith('.inc'): continue 91 | 92 | # open and read the file 93 | with open(os.path.join(dir, file_name)) as f: parse_file(f, trie) 94 | 95 | 96 | def parse_file(f: TextIOWrapper, trie: TrieRegEx) -> None: 97 | """ 98 | Parses a file for constants and adds them to the regex trie 99 | 100 | Args: 101 | f (TextIOWrapper): The file to parse 102 | tre (TrieRegEx): The trie to add results to. 103 | """ 104 | Debug.log('-- Reading from {} --'.format(f.name)) 105 | 106 | code: str = f.read() 107 | 108 | # remove multi-line comments 109 | code = re.sub(r'/\*(.|\n)*?\*/', '', code) 110 | #remove single-line comments 111 | code = re.sub(r'//.*$', '', code) 112 | 113 | parse_enums(code, trie) 114 | parse_defines(code, trie) 115 | parse_publicconstants(code, trie) 116 | 117 | 118 | def parse_enums(code: str, trie: TrieRegEx) -> None: 119 | """ 120 | Finds enum values and adds them to the regex trie 121 | 122 | Args: 123 | code (str): Text to search through. 124 | trie (TrieRegEx): Trie to add results to. 125 | """ 126 | # scoop the innards from all enums, excluding enum structs 127 | for enum_innards_match in re.finditer(r'enum(?!\s+struct)(?:.|\n)*?{((?:.|\n)*?)}', code): 128 | Debug.log('-- Enum match: --\n{}\n-------'.format(enum_innards_match.group(0))) 129 | enum_innards: str = enum_innards_match.group(1) 130 | 131 | # try to get each enum variable 132 | for enum_def_match in re.finditer(r'(?:^|\n)\s*?(\w+)\b', enum_innards): 133 | def_text: str = enum_def_match.group(1) 134 | 135 | # if it's all uppercase, skip it 136 | if (re.match(r'\b[A-Z_\d]+\b', def_text)): continue 137 | 138 | # skip if already contains 139 | if (trie.has(def_text)): 140 | Debug.log('Skipping enum, already added: {}'.format(def_text)) 141 | continue 142 | 143 | trie.add(def_text) 144 | Debug.log('Enum added: {}'.format(def_text)) 145 | 146 | 147 | def parse_defines(code: str, trie: TrieRegEx) -> None: 148 | """ 149 | Finds defines and adds them to the regex trie 150 | 151 | Args: 152 | code (str): Text to search through. 153 | trie (TrieRegEx): Trie to add results to. 154 | """ 155 | # match all defines 156 | for define_match in re.finditer(r'^#define[ \t]*(\w+)\b[ \t]', code): 157 | define: str = define_match.group(1) 158 | 159 | # if all uppercase, ignore. Typically they should be uppercase but maybe there's an exception 160 | if (re.match(r'\b[A-Z_\d]+\b', define)): continue 161 | 162 | # skip if already contains 163 | if (trie.has(define)): 164 | Debug.log('Skipping define, already added: {}'.format(define)) 165 | continue 166 | 167 | trie.add(define) 168 | Debug.log('Define added: {}'.format(define)) 169 | 170 | 171 | def parse_publicconstants(code: str, trie: TrieRegEx) -> None: 172 | """ 173 | Finds public const variables and adds them to the regex trie 174 | 175 | Args: 176 | code (str): Text to search through. 177 | trie (TrieRegEx): Trie to add results to. 178 | """ 179 | # match public constants aka magic variables 180 | for constant_match in re.finditer(r'public[ \t]+const[ \t]+\w+[ \t]+(\w+)\b', code): 181 | constant: str = constant_match.group(1) 182 | 183 | # if all uppercase, ignore 184 | if (re.match(r'\b[A-Z_\d]+\b', constant)): continue 185 | 186 | # skip if already contains 187 | if (trie.has(constant)): 188 | Debug.log('Skipping const, already added: {}'.format(constant)) 189 | continue 190 | 191 | trie.add(constant) 192 | Debug.log('Const added: {}'.format(constant)) 193 | 194 | 195 | # ------------- 196 | if __name__ == '__main__': main(parsedargs.paths) 197 | -------------------------------------------------------------------------------- /Packages/SourcePawn/notes.txt: -------------------------------------------------------------------------------- 1 | "sublime_text": ">4070" 2 | 3 | 2:20 PM] OdatNurd: 4 | >>> panel = window.create_output_panel('my_panel', unlisted=True) 5 | >>> panel.assign_syntax("Packages/Python/Python.sublime-syntax") 6 | >>> panel.run_command("append", {"characters": "import sublime"}) 7 | >>> panel.scope_name(0) 8 | 'source.python meta.statement.import.python keyword.control.import.python ' 9 | [2:21 PM] OdatNurd: also this may be a handy addition: 10 | [2:21 PM] OdatNurd: 11 | >>> panel.extract_tokens_with_scopes(sublime.Region(0, len(panel))) 12 | [((0, 6), 'source.python meta.statement.import.python keyword.control.import.python '), ((6, 7), 'source.python meta.statement.import.python '), ((7, 14), 'source.python meta.statement.import.python meta.qualified-name.python meta.generic-name.python ')] 13 | [2:22 PM] JoinedSenses: alright, thank you. another question. ive managed to grab a bunch of regions that consist of lets say, variable declarations. is there api to maybe split it up or grab all words within that region that are something like variable.other.readwrite 14 | [2:22 PM] OdatNurd: i.e. grab individual tokens with scopes applied over a region, which here is the whole panel content but you could target that 15 | [2:23 PM] OdatNurd: view.substr() gives you the text of any particular region as a string 16 | [2:24 PM] JoinedSenses: yeah, i've got the entire region as a string. trying to find a way to pull certain words from it 17 | [2:24 PM] OdatNurd: if you have say a region that covers a whole function and you just want the variables defined inside that, then you would need to do something like call view.find_by_selector('variable.other.readwrite') to get all of the variables, and then determine which of those results is inside of the region that wraps the function 18 | [2:24 PM] OdatNurd: region.contains() will tell you if one region contains another one 19 | [2:24 PM] JoinedSenses: cool thanks. that was my backup plan 20 | [2:25 PM] JoinedSenses: trying to do two things, get the type of variables and also only add variables in global and current local scope for autocompletion 21 | [2:26 PM] OdatNurd: depending on what you're trying to do, you could also combine this with the above; fill the hidden output panel with the function delcaration and then you're good to go. That may or may not be handy based on where and when you need the info though; also it requires that the syntax could still highlight things properly with only partial content, etc 22 | [2:26 PM] JoinedSenses: alright. i saved those references and will see if i can make sense/use of it 23 | [2:26 PM] JoinedSenses: thank you -------------------------------------------------------------------------------- /Packages/SourcePawn/pathtools/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # pathtools: File system path tools. 3 | # Copyright (C) 2010 Yesudeep Mangalapilly 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 | -------------------------------------------------------------------------------- /Packages/SourcePawn/pathtools/path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # path.py: Path functions. 4 | # 5 | # Copyright (C) 2010 Yesudeep Mangalapilly 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | """ 26 | :module: pathtools.path 27 | :synopsis: Directory walking, listing, and path sanitizing functions. 28 | :author: Yesudeep Mangalapilly 29 | 30 | Functions 31 | --------- 32 | .. autofunction:: get_dir_walker 33 | .. autofunction:: walk 34 | .. autofunction:: listdir 35 | .. autofunction:: list_directories 36 | .. autofunction:: list_files 37 | .. autofunction:: absolute_path 38 | .. autofunction:: real_absolute_path 39 | .. autofunction:: parent_dir_path 40 | """ 41 | 42 | import os.path 43 | from functools import partial 44 | 45 | 46 | __all__ = [ 47 | 'get_dir_walker', 48 | 'walk', 49 | 'listdir', 50 | 'list_directories', 51 | 'list_files', 52 | 'absolute_path', 53 | 'real_absolute_path', 54 | 'parent_dir_path', 55 | ] 56 | 57 | 58 | def get_dir_walker(recursive, topdown=True, followlinks=False): 59 | """ 60 | Returns a recursive or a non-recursive directory walker. 61 | 62 | :param recursive: 63 | ``True`` produces a recursive walker; ``False`` produces a non-recursive 64 | walker. 65 | :returns: 66 | A walker function. 67 | """ 68 | if recursive: 69 | walk = partial(os.walk, topdown=topdown, followlinks=followlinks) 70 | else: 71 | def walk(path, topdown=topdown, followlinks=followlinks): 72 | try: 73 | yield next(os.walk(path, topdown=topdown, followlinks=followlinks)) 74 | except NameError: 75 | yield os.walk(path, topdown=topdown, followlinks=followlinks).next() #IGNORE:E1101 76 | return walk 77 | 78 | 79 | def walk(dir_pathname, recursive=True, topdown=True, followlinks=False): 80 | """ 81 | Walks a directory tree optionally recursively. Works exactly like 82 | :func:`os.walk` only adding the `recursive` argument. 83 | 84 | :param dir_pathname: 85 | The directory to traverse. 86 | :param recursive: 87 | ``True`` for walking recursively through the directory tree; 88 | ``False`` otherwise. 89 | :param topdown: 90 | Please see the documentation for :func:`os.walk` 91 | :param followlinks: 92 | Please see the documentation for :func:`os.walk` 93 | """ 94 | walk_func = get_dir_walker(recursive, topdown, followlinks) 95 | for root, dirnames, filenames in walk_func(dir_pathname): 96 | yield (root, dirnames, filenames) 97 | 98 | 99 | def listdir(dir_pathname, 100 | recursive=True, 101 | topdown=True, 102 | followlinks=False): 103 | """ 104 | Enlists all items using their absolute paths in a directory, optionally 105 | recursively. 106 | 107 | :param dir_pathname: 108 | The directory to traverse. 109 | :param recursive: 110 | ``True`` for walking recursively through the directory tree; 111 | ``False`` otherwise. 112 | :param topdown: 113 | Please see the documentation for :func:`os.walk` 114 | :param followlinks: 115 | Please see the documentation for :func:`os.walk` 116 | """ 117 | for root, dirnames, filenames\ 118 | in walk(dir_pathname, recursive, topdown, followlinks): 119 | for dirname in dirnames: 120 | yield absolute_path(os.path.join(root, dirname)) 121 | for filename in filenames: 122 | yield absolute_path(os.path.join(root, filename)) 123 | 124 | 125 | def list_directories(dir_pathname, 126 | recursive=True, 127 | topdown=True, 128 | followlinks=False): 129 | """ 130 | Enlists all the directories using their absolute paths within the specified 131 | directory, optionally recursively. 132 | 133 | :param dir_pathname: 134 | The directory to traverse. 135 | :param recursive: 136 | ``True`` for walking recursively through the directory tree; 137 | ``False`` otherwise. 138 | :param topdown: 139 | Please see the documentation for :func:`os.walk` 140 | :param followlinks: 141 | Please see the documentation for :func:`os.walk` 142 | """ 143 | for root, dirnames, filenames\ 144 | in walk(dir_pathname, recursive, topdown, followlinks): 145 | for dirname in dirnames: 146 | yield absolute_path(os.path.join(root, dirname)) 147 | 148 | 149 | def list_files(dir_pathname, 150 | recursive=True, 151 | topdown=True, 152 | followlinks=False): 153 | """ 154 | Enlists all the files using their absolute paths within the specified 155 | directory, optionally recursively. 156 | 157 | :param dir_pathname: 158 | The directory to traverse. 159 | :param recursive: 160 | ``True`` for walking recursively through the directory tree; 161 | ``False`` otherwise. 162 | :param topdown: 163 | Please see the documentation for :func:`os.walk` 164 | :param followlinks: 165 | Please see the documentation for :func:`os.walk` 166 | """ 167 | for root, dirnames, filenames\ 168 | in walk(dir_pathname, recursive, topdown, followlinks): 169 | for filename in filenames: 170 | yield absolute_path(os.path.join(root, filename)) 171 | 172 | 173 | def absolute_path(path): 174 | """ 175 | Returns the absolute path for the given path and normalizes the path. 176 | 177 | :param path: 178 | Path for which the absolute normalized path will be found. 179 | :returns: 180 | Absolute normalized path. 181 | """ 182 | return os.path.abspath(os.path.normpath(path)) 183 | 184 | 185 | def real_absolute_path(path): 186 | """ 187 | Returns the real absolute normalized path for the given path. 188 | 189 | :param path: 190 | Path for which the real absolute normalized path will be found. 191 | :returns: 192 | Real absolute normalized path. 193 | """ 194 | return os.path.realpath(absolute_path(path)) 195 | 196 | 197 | def parent_dir_path(path): 198 | """ 199 | Returns the parent directory path. 200 | 201 | :param path: 202 | Path for which the parent directory will be obtained. 203 | :returns: 204 | Parent directory path. 205 | """ 206 | return absolute_path(os.path.dirname(path)) 207 | -------------------------------------------------------------------------------- /Packages/SourcePawn/pathtools/patterns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # patterns.py: Common wildcard searching/filtering functionality for files. 4 | # 5 | # Copyright (C) 2010 Yesudeep Mangalapilly 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | """ 26 | :module: pathtools.patterns 27 | :synopsis: Wildcard pattern matching and filtering functions for paths. 28 | :author: Yesudeep Mangalapilly 29 | 30 | Functions 31 | --------- 32 | .. autofunction:: match_path 33 | .. autofunction:: match_path_against 34 | .. autofunction:: filter_paths 35 | """ 36 | 37 | from fnmatch import fnmatch, fnmatchcase 38 | 39 | __all__ = ['match_path', 40 | 'match_path_against', 41 | 'match_any_paths', 42 | 'filter_paths'] 43 | 44 | 45 | def _string_lower(s): 46 | """ 47 | Convenience function to lowercase a string (the :mod:`string` module is 48 | deprecated/removed in Python 3.0). 49 | 50 | :param s: 51 | The string which will be lowercased. 52 | :returns: 53 | Lowercased copy of string s. 54 | """ 55 | return s.lower() 56 | 57 | 58 | def match_path_against(pathname, patterns, case_sensitive=True): 59 | """ 60 | Determines whether the pathname matches any of the given wildcard patterns, 61 | optionally ignoring the case of the pathname and patterns. 62 | 63 | :param pathname: 64 | A path name that will be matched against a wildcard pattern. 65 | :param patterns: 66 | A list of wildcard patterns to match_path the filename against. 67 | :param case_sensitive: 68 | ``True`` if the matching should be case-sensitive; ``False`` otherwise. 69 | :returns: 70 | ``True`` if the pattern matches; ``False`` otherwise. 71 | 72 | Doctests:: 73 | >>> match_path_against("/home/username/foobar/blah.py", ["*.py", "*.txt"], False) 74 | True 75 | >>> match_path_against("/home/username/foobar/blah.py", ["*.PY", "*.txt"], True) 76 | False 77 | >>> match_path_against("/home/username/foobar/blah.py", ["*.PY", "*.txt"], False) 78 | True 79 | >>> match_path_against("C:\\windows\\blah\\BLAH.PY", ["*.py", "*.txt"], True) 80 | False 81 | >>> match_path_against("C:\\windows\\blah\\BLAH.PY", ["*.py", "*.txt"], False) 82 | True 83 | """ 84 | if case_sensitive: 85 | match_func = fnmatchcase 86 | pattern_transform_func = (lambda w: w) 87 | else: 88 | match_func = fnmatch 89 | pathname = pathname.lower() 90 | pattern_transform_func = _string_lower 91 | for pattern in set(patterns): 92 | pattern = pattern_transform_func(pattern) 93 | if match_func(pathname, pattern): 94 | return True 95 | return False 96 | 97 | 98 | def _match_path(pathname, 99 | included_patterns, 100 | excluded_patterns, 101 | case_sensitive=True): 102 | """Internal function same as :func:`match_path` but does not check arguments. 103 | 104 | Doctests:: 105 | >>> _match_path("/users/gorakhargosh/foobar.py", ["*.py"], ["*.PY"], True) 106 | True 107 | >>> _match_path("/users/gorakhargosh/FOOBAR.PY", ["*.py"], ["*.PY"], True) 108 | False 109 | >>> _match_path("/users/gorakhargosh/foobar/", ["*.py"], ["*.txt"], False) 110 | False 111 | >>> _match_path("/users/gorakhargosh/FOOBAR.PY", ["*.py"], ["*.PY"], False) 112 | Traceback (most recent call last): 113 | ... 114 | ValueError: conflicting patterns `set(['*.py'])` included and excluded 115 | """ 116 | if not case_sensitive: 117 | included_patterns = set(map(_string_lower, included_patterns)) 118 | excluded_patterns = set(map(_string_lower, excluded_patterns)) 119 | else: 120 | included_patterns = set(included_patterns) 121 | excluded_patterns = set(excluded_patterns) 122 | common_patterns = included_patterns & excluded_patterns 123 | if common_patterns: 124 | raise ValueError('conflicting patterns `%s` included and excluded'\ 125 | % common_patterns) 126 | return (match_path_against(pathname, included_patterns, case_sensitive)\ 127 | and not match_path_against(pathname, excluded_patterns, 128 | case_sensitive)) 129 | 130 | 131 | def match_path(pathname, 132 | included_patterns=None, 133 | excluded_patterns=None, 134 | case_sensitive=True): 135 | """ 136 | Matches a pathname against a set of acceptable and ignored patterns. 137 | 138 | :param pathname: 139 | A pathname which will be matched against a pattern. 140 | :param included_patterns: 141 | Allow filenames matching wildcard patterns specified in this list. 142 | If no pattern is specified, the function treats the pathname as 143 | a match_path. 144 | :param excluded_patterns: 145 | Ignores filenames matching wildcard patterns specified in this list. 146 | If no pattern is specified, the function treats the pathname as 147 | a match_path. 148 | :param case_sensitive: 149 | ``True`` if matching should be case-sensitive; ``False`` otherwise. 150 | :returns: 151 | ``True`` if the pathname matches; ``False`` otherwise. 152 | :raises: 153 | ValueError if included patterns and excluded patterns contain the 154 | same pattern. 155 | 156 | Doctests:: 157 | >>> match_path("/Users/gorakhargosh/foobar.py") 158 | True 159 | >>> match_path("/Users/gorakhargosh/foobar.py", case_sensitive=False) 160 | True 161 | >>> match_path("/users/gorakhargosh/foobar.py", ["*.py"], ["*.PY"], True) 162 | True 163 | >>> match_path("/users/gorakhargosh/FOOBAR.PY", ["*.py"], ["*.PY"], True) 164 | False 165 | >>> match_path("/users/gorakhargosh/foobar/", ["*.py"], ["*.txt"], False) 166 | False 167 | >>> match_path("/users/gorakhargosh/FOOBAR.PY", ["*.py"], ["*.PY"], False) 168 | Traceback (most recent call last): 169 | ... 170 | ValueError: conflicting patterns `set(['*.py'])` included and excluded 171 | """ 172 | included = ["*"] if included_patterns is None else included_patterns 173 | excluded = [] if excluded_patterns is None else excluded_patterns 174 | return _match_path(pathname, included, excluded, case_sensitive) 175 | 176 | 177 | def filter_paths(pathnames, 178 | included_patterns=None, 179 | excluded_patterns=None, 180 | case_sensitive=True): 181 | """ 182 | Filters from a set of paths based on acceptable patterns and 183 | ignorable patterns. 184 | 185 | :param pathnames: 186 | A list of path names that will be filtered based on matching and 187 | ignored patterns. 188 | :param included_patterns: 189 | Allow filenames matching wildcard patterns specified in this list. 190 | If no pattern list is specified, ["*"] is used as the default pattern, 191 | which matches all files. 192 | :param excluded_patterns: 193 | Ignores filenames matching wildcard patterns specified in this list. 194 | If no pattern list is specified, no files are ignored. 195 | :param case_sensitive: 196 | ``True`` if matching should be case-sensitive; ``False`` otherwise. 197 | :returns: 198 | A list of pathnames that matched the allowable patterns and passed 199 | through the ignored patterns. 200 | 201 | Doctests:: 202 | >>> pathnames = set(["/users/gorakhargosh/foobar.py", "/var/cache/pdnsd.status", "/etc/pdnsd.conf", "/usr/local/bin/python"]) 203 | >>> set(filter_paths(pathnames)) == pathnames 204 | True 205 | >>> set(filter_paths(pathnames, case_sensitive=False)) == pathnames 206 | True 207 | >>> set(filter_paths(pathnames, ["*.py", "*.conf"], ["*.status"], case_sensitive=True)) == set(["/users/gorakhargosh/foobar.py", "/etc/pdnsd.conf"]) 208 | True 209 | """ 210 | included = ["*"] if included_patterns is None else included_patterns 211 | excluded = [] if excluded_patterns is None else excluded_patterns 212 | 213 | for pathname in pathnames: 214 | # We don't call the public match_path because it checks arguments 215 | # and sets default values if none are found. We're already doing that 216 | # above. 217 | if _match_path(pathname, included, excluded, case_sensitive): 218 | yield pathname 219 | 220 | def match_any_paths(pathnames, 221 | included_patterns=None, 222 | excluded_patterns=None, 223 | case_sensitive=True): 224 | """ 225 | Matches from a set of paths based on acceptable patterns and 226 | ignorable patterns. 227 | 228 | :param pathnames: 229 | A list of path names that will be filtered based on matching and 230 | ignored patterns. 231 | :param included_patterns: 232 | Allow filenames matching wildcard patterns specified in this list. 233 | If no pattern list is specified, ["*"] is used as the default pattern, 234 | which matches all files. 235 | :param excluded_patterns: 236 | Ignores filenames matching wildcard patterns specified in this list. 237 | If no pattern list is specified, no files are ignored. 238 | :param case_sensitive: 239 | ``True`` if matching should be case-sensitive; ``False`` otherwise. 240 | :returns: 241 | ``True`` if any of the paths matches; ``False`` otherwise. 242 | 243 | Doctests:: 244 | >>> pathnames = set(["/users/gorakhargosh/foobar.py", "/var/cache/pdnsd.status", "/etc/pdnsd.conf", "/usr/local/bin/python"]) 245 | >>> match_any_paths(pathnames) 246 | True 247 | >>> match_any_paths(pathnames, case_sensitive=False) 248 | True 249 | >>> match_any_paths(pathnames, ["*.py", "*.conf"], ["*.status"], case_sensitive=True) 250 | True 251 | >>> match_any_paths(pathnames, ["*.txt"], case_sensitive=False) 252 | False 253 | >>> match_any_paths(pathnames, ["*.txt"], case_sensitive=True) 254 | False 255 | """ 256 | included = ["*"] if included_patterns is None else included_patterns 257 | excluded = [] if excluded_patterns is None else excluded_patterns 258 | 259 | for pathname in pathnames: 260 | # We don't call the public match_path because it checks arguments 261 | # and sets default values if none are found. We're already doing that 262 | # above. 263 | if _match_path(pathname, included, excluded, case_sensitive): 264 | return True 265 | return False 266 | -------------------------------------------------------------------------------- /Packages/SourcePawn/pathtools/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # version.py: Version information. 3 | # Copyright (C) 2010 Yesudeep Mangalapilly 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 | 23 | # When updating this version number, please update the 24 | # ``docs/source/global.rst.inc`` file as well. 25 | VERSION_MAJOR = 0 26 | VERSION_MINOR = 1 27 | VERSION_BUILD = 1 28 | VERSION_INFO = (VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD) 29 | VERSION_STRING = "%d.%d.%d" % VERSION_INFO 30 | 31 | __version__ = VERSION_INFO 32 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | """ 20 | :module: watchdog.observers 21 | :synopsis: Observer that picks a native implementation if available. 22 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 23 | 24 | 25 | Classes 26 | ======= 27 | .. autoclass:: Observer 28 | :members: 29 | :show-inheritance: 30 | :inherited-members: 31 | 32 | Observer thread that schedules watching directories and dispatches 33 | calls to event handlers. 34 | 35 | You can also import platform specific classes directly and use it instead 36 | of :class:`Observer`. Here is a list of implemented observer classes.: 37 | 38 | ============== ================================ ============================== 39 | Class Platforms Note 40 | ============== ================================ ============================== 41 | |Inotify| Linux 2.6.13+ ``inotify(7)`` based observer 42 | |FSEvents| Mac OS X FSEvents based observer 43 | |Kqueue| Mac OS X and BSD with kqueue(2) ``kqueue(2)`` based observer 44 | |WinApi| MS Windows Windows API-based observer 45 | |Polling| Any fallback implementation 46 | ============== ================================ ============================== 47 | 48 | .. |Inotify| replace:: :class:`.inotify.InotifyObserver` 49 | .. |FSEvents| replace:: :class:`.fsevents.FSEventsObserver` 50 | .. |Kqueue| replace:: :class:`.kqueue.KqueueObserver` 51 | .. |WinApi| replace:: :class:`.read_directory_changes.WindowsApiObserver` 52 | .. |WinApiAsync| replace:: :class:`.read_directory_changes_async.WindowsApiAsyncObserver` 53 | .. |Polling| replace:: :class:`.polling.PollingObserver` 54 | 55 | """ 56 | 57 | import warnings 58 | from watchdog.utils import platform 59 | 60 | if platform.is_linux(): 61 | from .inotify import InotifyObserver as Observer 62 | 63 | elif platform.is_darwin(): 64 | try: 65 | from .fsevents import FSEventsObserver as Observer 66 | except: 67 | from .kqueue import KqueueObserver as Observer 68 | warnings.warn("Failed to import fsevents. Fall back to kqueue") 69 | 70 | elif platform.is_bsd(): 71 | from .kqueue import KqueueObserver as Observer 72 | 73 | elif platform.is_windows(): 74 | # TODO: find a reliable way of checking Windows version and import 75 | # polling explicitly for Windows XP 76 | try: 77 | from .read_directory_changes import WindowsApiObserver as Observer 78 | except: 79 | from .polling import PollingObserver as Observer 80 | warnings.warn("Failed to import read_directory_changes. Fall back to polling.") 81 | 82 | else: 83 | from .polling import PollingObserver as Observer 84 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/fsevents.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | """ 20 | :module: watchdog.observers.fsevents 21 | :synopsis: FSEvents based emitter implementation. 22 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 23 | :platforms: Mac OS X 24 | """ 25 | 26 | from __future__ import with_statement 27 | 28 | import sys 29 | import threading 30 | import unicodedata 31 | import _watchdog_fsevents as _fsevents 32 | 33 | from watchdog.events import ( 34 | FileDeletedEvent, 35 | FileModifiedEvent, 36 | FileCreatedEvent, 37 | FileMovedEvent, 38 | DirDeletedEvent, 39 | DirModifiedEvent, 40 | DirCreatedEvent, 41 | DirMovedEvent 42 | ) 43 | 44 | from watchdog.utils.dirsnapshot import DirectorySnapshot 45 | from watchdog.observers.api import ( 46 | BaseObserver, 47 | EventEmitter, 48 | DEFAULT_EMITTER_TIMEOUT, 49 | DEFAULT_OBSERVER_TIMEOUT 50 | ) 51 | 52 | 53 | class FSEventsEmitter(EventEmitter): 54 | 55 | """ 56 | Mac OS X FSEvents Emitter class. 57 | 58 | :param event_queue: 59 | The event queue to fill with events. 60 | :param watch: 61 | A watch object representing the directory to monitor. 62 | :type watch: 63 | :class:`watchdog.observers.api.ObservedWatch` 64 | :param timeout: 65 | Read events blocking timeout (in seconds). 66 | :type timeout: 67 | ``float`` 68 | """ 69 | 70 | def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT): 71 | EventEmitter.__init__(self, event_queue, watch, timeout) 72 | self._lock = threading.Lock() 73 | self.snapshot = DirectorySnapshot(watch.path, watch.is_recursive) 74 | 75 | def on_thread_stop(self): 76 | _fsevents.remove_watch(self.watch) 77 | _fsevents.stop(self) 78 | 79 | def queue_events(self, timeout): 80 | with self._lock: 81 | if not self.watch.is_recursive\ 82 | and self.watch.path not in self.pathnames: 83 | return 84 | new_snapshot = DirectorySnapshot(self.watch.path, 85 | self.watch.is_recursive) 86 | events = new_snapshot - self.snapshot 87 | self.snapshot = new_snapshot 88 | 89 | # Files. 90 | for src_path in events.files_deleted: 91 | self.queue_event(FileDeletedEvent(src_path)) 92 | for src_path in events.files_modified: 93 | self.queue_event(FileModifiedEvent(src_path)) 94 | for src_path in events.files_created: 95 | self.queue_event(FileCreatedEvent(src_path)) 96 | for src_path, dest_path in events.files_moved: 97 | self.queue_event(FileMovedEvent(src_path, dest_path)) 98 | 99 | # Directories. 100 | for src_path in events.dirs_deleted: 101 | self.queue_event(DirDeletedEvent(src_path)) 102 | for src_path in events.dirs_modified: 103 | self.queue_event(DirModifiedEvent(src_path)) 104 | for src_path in events.dirs_created: 105 | self.queue_event(DirCreatedEvent(src_path)) 106 | for src_path, dest_path in events.dirs_moved: 107 | self.queue_event(DirMovedEvent(src_path, dest_path)) 108 | 109 | def run(self): 110 | try: 111 | def callback(pathnames, flags, emitter=self): 112 | emitter.queue_events(emitter.timeout) 113 | 114 | # for pathname, flag in zip(pathnames, flags): 115 | # if emitter.watch.is_recursive: # and pathname != emitter.watch.path: 116 | # new_sub_snapshot = DirectorySnapshot(pathname, True) 117 | # old_sub_snapshot = self.snapshot.copy(pathname) 118 | # diff = new_sub_snapshot - old_sub_snapshot 119 | # self.snapshot += new_subsnapshot 120 | # else: 121 | # new_snapshot = DirectorySnapshot(emitter.watch.path, False) 122 | # diff = new_snapshot - emitter.snapshot 123 | # emitter.snapshot = new_snapshot 124 | 125 | # INFO: FSEvents reports directory notifications recursively 126 | # by default, so we do not need to add subdirectory paths. 127 | #pathnames = set([self.watch.path]) 128 | # if self.watch.is_recursive: 129 | # for root, directory_names, _ in os.walk(self.watch.path): 130 | # for directory_name in directory_names: 131 | # full_path = absolute_path( 132 | # os.path.join(root, directory_name)) 133 | # pathnames.add(full_path) 134 | self.pathnames = [self.watch.path] 135 | _fsevents.add_watch(self, 136 | self.watch, 137 | callback, 138 | self.pathnames) 139 | _fsevents.read_events(self) 140 | except Exception as e: 141 | pass 142 | 143 | 144 | class FSEventsObserver(BaseObserver): 145 | 146 | def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): 147 | BaseObserver.__init__(self, emitter_class=FSEventsEmitter, 148 | timeout=timeout) 149 | 150 | def schedule(self, event_handler, path, recursive=False): 151 | # Python 2/3 compat 152 | try: 153 | str_class = unicode 154 | except NameError: 155 | str_class = str 156 | 157 | # Fix for issue #26: Trace/BPT error when given a unicode path 158 | # string. https://github.com/gorakhargosh/watchdog/issues#issue/26 159 | if isinstance(path, str_class): 160 | #path = unicode(path, 'utf-8') 161 | path = unicodedata.normalize('NFC', path) 162 | # We only encode the path in Python 2 for backwards compatibility. 163 | # On Python 3 we want the path to stay as unicode if possible for 164 | # the sake of path matching not having to be rewritten to use the 165 | # bytes API instead of strings. The _watchdog_fsevent.so code for 166 | # Python 3 can handle both str and bytes paths, which is why we 167 | # do not HAVE to encode it with Python 3. The Python 2 code in 168 | # _watchdog_fsevents.so was not changed for the sake of backwards 169 | # compatibility. 170 | if sys.version_info < (3,): 171 | path = path.encode('utf-8') 172 | return BaseObserver.schedule(self, event_handler, path, recursive) 173 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/fsevents2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2014 Thomas Amland 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """ 18 | :module: watchdog.observers.fsevents2 19 | :synopsis: FSEvents based emitter implementation. 20 | :platforms: Mac OS X 21 | """ 22 | 23 | import os 24 | import logging 25 | import unicodedata 26 | from threading import Thread 27 | from watchdog.utils.compat import queue 28 | 29 | from watchdog.events import ( 30 | FileDeletedEvent, 31 | FileModifiedEvent, 32 | FileCreatedEvent, 33 | FileMovedEvent, 34 | DirDeletedEvent, 35 | DirModifiedEvent, 36 | DirCreatedEvent, 37 | DirMovedEvent 38 | ) 39 | from watchdog.observers.api import ( 40 | BaseObserver, 41 | EventEmitter, 42 | DEFAULT_EMITTER_TIMEOUT, 43 | DEFAULT_OBSERVER_TIMEOUT, 44 | ) 45 | 46 | # pyobjc 47 | import AppKit 48 | from FSEvents import ( 49 | FSEventStreamCreate, 50 | CFRunLoopGetCurrent, 51 | FSEventStreamScheduleWithRunLoop, 52 | FSEventStreamStart, 53 | CFRunLoopRun, 54 | CFRunLoopStop, 55 | FSEventStreamStop, 56 | FSEventStreamInvalidate, 57 | FSEventStreamRelease, 58 | ) 59 | 60 | from FSEvents import ( 61 | kCFAllocatorDefault, 62 | kCFRunLoopDefaultMode, 63 | kFSEventStreamEventIdSinceNow, 64 | kFSEventStreamCreateFlagNoDefer, 65 | kFSEventStreamCreateFlagFileEvents, 66 | kFSEventStreamEventFlagItemCreated, 67 | kFSEventStreamEventFlagItemRemoved, 68 | kFSEventStreamEventFlagItemInodeMetaMod, 69 | kFSEventStreamEventFlagItemRenamed, 70 | kFSEventStreamEventFlagItemModified, 71 | kFSEventStreamEventFlagItemFinderInfoMod, 72 | kFSEventStreamEventFlagItemChangeOwner, 73 | kFSEventStreamEventFlagItemXattrMod, 74 | kFSEventStreamEventFlagItemIsFile, 75 | kFSEventStreamEventFlagItemIsDir, 76 | kFSEventStreamEventFlagItemIsSymlink, 77 | ) 78 | 79 | 80 | class FSEventsQueue(Thread): 81 | """ Low level FSEvents client. """ 82 | 83 | def __init__(self, path): 84 | Thread.__init__(self) 85 | self._queue = queue.Queue() 86 | self._run_loop = None 87 | 88 | if isinstance(path, bytes): 89 | self._path = path.decode('utf-8') 90 | self._path = unicodedata.normalize('NFC', self._path) 91 | 92 | context = None 93 | latency = 1.0 94 | self._stream_ref = FSEventStreamCreate( 95 | kCFAllocatorDefault, self._callback, context, [self._path], 96 | kFSEventStreamEventIdSinceNow, latency, 97 | kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents) 98 | if self._stream_ref is None: 99 | raise IOError("FSEvents. Could not create stream.") 100 | 101 | def run(self): 102 | pool = AppKit.NSAutoreleasePool.alloc().init() 103 | self._run_loop = CFRunLoopGetCurrent() 104 | FSEventStreamScheduleWithRunLoop( 105 | self._stream_ref, self._run_loop, kCFRunLoopDefaultMode) 106 | if not FSEventStreamStart(self._stream_ref): 107 | FSEventStreamInvalidate(self._stream_ref) 108 | FSEventStreamRelease(self._stream_ref) 109 | raise IOError("FSEvents. Could not start stream.") 110 | 111 | CFRunLoopRun() 112 | FSEventStreamStop(self._stream_ref) 113 | FSEventStreamInvalidate(self._stream_ref) 114 | FSEventStreamRelease(self._stream_ref) 115 | del pool 116 | # Make sure waiting thread is notified 117 | self._queue.put(None) 118 | 119 | def stop(self): 120 | if self._run_loop is not None: 121 | CFRunLoopStop(self._run_loop) 122 | 123 | def _callback(self, streamRef, clientCallBackInfo, numEvents, eventPaths, eventFlags, eventIDs): 124 | events = [NativeEvent(path, flags, _id) for path, flags, _id in 125 | zip(eventPaths, eventFlags, eventIDs)] 126 | logging.debug("FSEvents callback. Got %d events:" % numEvents) 127 | for e in events: 128 | logging.debug(e) 129 | self._queue.put(events) 130 | 131 | def read_events(self): 132 | """ 133 | Returns a list or one or more events, or None if there are no more 134 | events to be read. 135 | """ 136 | if not self.is_alive(): 137 | return None 138 | return self._queue.get() 139 | 140 | 141 | class NativeEvent(object): 142 | def __init__(self, path, flags, event_id): 143 | self.path = path 144 | self.flags = flags 145 | self.event_id = event_id 146 | self.is_created = bool(flags & kFSEventStreamEventFlagItemCreated) 147 | self.is_removed = bool(flags & kFSEventStreamEventFlagItemRemoved) 148 | self.is_renamed = bool(flags & kFSEventStreamEventFlagItemRenamed) 149 | self.is_modified = bool(flags & kFSEventStreamEventFlagItemModified) 150 | self.is_change_owner = bool(flags & kFSEventStreamEventFlagItemChangeOwner) 151 | self.is_inode_meta_mod = bool(flags & kFSEventStreamEventFlagItemInodeMetaMod) 152 | self.is_finder_info_mod = bool(flags & kFSEventStreamEventFlagItemFinderInfoMod) 153 | self.is_xattr_mod = bool(flags & kFSEventStreamEventFlagItemXattrMod) 154 | self.is_symlink = bool(flags & kFSEventStreamEventFlagItemIsSymlink) 155 | self.is_directory = bool(flags & kFSEventStreamEventFlagItemIsDir) 156 | 157 | @property 158 | def _event_type(self): 159 | if self.is_created: return "Created" 160 | if self.is_removed: return "Removed" 161 | if self.is_renamed: return "Renamed" 162 | if self.is_modified: return "Modified" 163 | if self.is_inode_meta_mod: return "InodeMetaMod" 164 | if self.is_xattr_mod: return "XattrMod" 165 | return "Unknown" 166 | 167 | def __repr__(self): 168 | s ="" 169 | return s % (repr(self.path), self._event_type, self.is_directory, hex(self.flags), self.event_id) 170 | 171 | 172 | class FSEventsEmitter(EventEmitter): 173 | """ 174 | FSEvents based event emitter. Handles conversion of native events. 175 | """ 176 | 177 | def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT): 178 | EventEmitter.__init__(self, event_queue, watch, timeout) 179 | self._fsevents = FSEventsQueue(watch.path) 180 | self._fsevents.start() 181 | 182 | def on_thread_stop(self): 183 | self._fsevents.stop() 184 | 185 | def queue_events(self, timeout): 186 | events = self._fsevents.read_events() 187 | if events is None: 188 | return 189 | i = 0 190 | while i < len(events): 191 | event = events[i] 192 | 193 | # For some reason the create and remove flags are sometimes also 194 | # set for rename and modify type events, so let those take 195 | # precedence. 196 | if event.is_renamed: 197 | # Internal moves appears to always be consecutive in the same 198 | # buffer and have IDs differ by exactly one (while others 199 | # don't) making it possible to pair up the two events coming 200 | # from a singe move operation. (None of this is documented!) 201 | # Otherwise, guess whether file was moved in or out. 202 | #TODO: handle id wrapping 203 | if (i+1 < len(events) and events[i+1].is_renamed and 204 | events[i+1].event_id == event.event_id + 1): 205 | cls = DirMovedEvent if event.is_directory else FileMovedEvent 206 | self.queue_event(cls(event.path, events[i+1].path)) 207 | self.queue_event(DirModifiedEvent(os.path.dirname(event.path))) 208 | self.queue_event(DirModifiedEvent(os.path.dirname(events[i+1].path))) 209 | i += 1 210 | elif os.path.exists(event.path): 211 | cls = DirCreatedEvent if event.is_directory else FileCreatedEvent 212 | self.queue_event(cls(event.path)) 213 | self.queue_event(DirModifiedEvent(os.path.dirname(event.path))) 214 | else: 215 | cls = DirDeletedEvent if event.is_directory else FileDeletedEvent 216 | self.queue_event(cls(event.path)) 217 | self.queue_event(DirModifiedEvent(os.path.dirname(event.path))) 218 | #TODO: generate events for tree 219 | 220 | elif event.is_modified or event.is_inode_meta_mod or event.is_xattr_mod : 221 | cls = DirModifiedEvent if event.is_directory else FileModifiedEvent 222 | self.queue_event(cls(event.path)) 223 | 224 | elif event.is_created: 225 | cls = DirCreatedEvent if event.is_directory else FileCreatedEvent 226 | self.queue_event(cls(event.path)) 227 | self.queue_event(DirModifiedEvent(os.path.dirname(event.path))) 228 | 229 | elif event.is_removed: 230 | cls = DirDeletedEvent if event.is_directory else FileDeletedEvent 231 | self.queue_event(cls(event.path)) 232 | self.queue_event(DirModifiedEvent(os.path.dirname(event.path))) 233 | i += 1 234 | 235 | 236 | class FSEventsObserver2(BaseObserver): 237 | def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): 238 | BaseObserver.__init__(self, emitter_class=FSEventsEmitter, timeout=timeout) 239 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/inotify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | """ 20 | :module: watchdog.observers.inotify 21 | :synopsis: ``inotify(7)`` based emitter implementation. 22 | :author: Sebastien Martini 23 | :author: Luke McCarthy 24 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 25 | :author: Tim Cuthbertson 26 | :platforms: Linux 2.6.13+. 27 | 28 | .. ADMONITION:: About system requirements 29 | 30 | Recommended minimum kernel version: 2.6.25. 31 | 32 | Quote from the inotify(7) man page: 33 | 34 | "Inotify was merged into the 2.6.13 Linux kernel. The required library 35 | interfaces were added to glibc in version 2.4. (IN_DONT_FOLLOW, 36 | IN_MASK_ADD, and IN_ONLYDIR were only added in version 2.5.)" 37 | 38 | Therefore, you must ensure the system is running at least these versions 39 | appropriate libraries and the kernel. 40 | 41 | .. ADMONITION:: About recursiveness, event order, and event coalescing 42 | 43 | Quote from the inotify(7) man page: 44 | 45 | If successive output inotify events produced on the inotify file 46 | descriptor are identical (same wd, mask, cookie, and name) then they 47 | are coalesced into a single event if the older event has not yet been 48 | read (but see BUGS). 49 | 50 | The events returned by reading from an inotify file descriptor form 51 | an ordered queue. Thus, for example, it is guaranteed that when 52 | renaming from one directory to another, events will be produced in 53 | the correct order on the inotify file descriptor. 54 | 55 | ... 56 | 57 | Inotify monitoring of directories is not recursive: to monitor 58 | subdirectories under a directory, additional watches must be created. 59 | 60 | This emitter implementation therefore automatically adds watches for 61 | sub-directories if running in recursive mode. 62 | 63 | Some extremely useful articles and documentation: 64 | 65 | .. _inotify FAQ: http://inotify.aiken.cz/?section=inotify&page=faq&lang=en 66 | .. _intro to inotify: http://www.linuxjournal.com/article/8478 67 | 68 | """ 69 | 70 | from __future__ import with_statement 71 | 72 | import os 73 | import threading 74 | from .inotify_buffer import InotifyBuffer, STOP_EVENT 75 | 76 | from watchdog.observers.api import ( 77 | EventEmitter, 78 | BaseObserver, 79 | DEFAULT_EMITTER_TIMEOUT, 80 | DEFAULT_OBSERVER_TIMEOUT 81 | ) 82 | 83 | from watchdog.events import ( 84 | DirDeletedEvent, 85 | DirModifiedEvent, 86 | DirMovedEvent, 87 | DirCreatedEvent, 88 | FileDeletedEvent, 89 | FileModifiedEvent, 90 | FileMovedEvent, 91 | FileCreatedEvent, 92 | generate_sub_moved_events, 93 | generate_sub_created_events, 94 | ) 95 | from watchdog.utils import unicode_paths 96 | 97 | 98 | class InotifyEmitter(EventEmitter): 99 | """ 100 | inotify(7)-based event emitter. 101 | 102 | :param event_queue: 103 | The event queue to fill with events. 104 | :param watch: 105 | A watch object representing the directory to monitor. 106 | :type watch: 107 | :class:`watchdog.observers.api.ObservedWatch` 108 | :param timeout: 109 | Read events blocking timeout (in seconds). 110 | :type timeout: 111 | ``float`` 112 | """ 113 | 114 | def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT): 115 | EventEmitter.__init__(self, event_queue, watch, timeout) 116 | self._lock = threading.Lock() 117 | self._inotify = InotifyBuffer(unicode_paths.encode(watch.path), 118 | watch.is_recursive) 119 | 120 | def _decode_path(self, path): 121 | """ Decode path only if unicode string was passed to this emitter. """ 122 | if isinstance(self.watch.path, bytes): 123 | return path 124 | return unicode_paths.decode(path) 125 | 126 | def on_thread_stop(self): 127 | self._inotify.close() 128 | 129 | def queue_events(self, timeout): 130 | with self._lock: 131 | event = self._inotify.read_event() 132 | 133 | if event is STOP_EVENT: 134 | return 135 | 136 | if isinstance(event, tuple): 137 | move_from, move_to = event 138 | src_path = self._decode_path(move_from.src_path) 139 | dest_path = self._decode_path(move_to.src_path) 140 | cls = DirMovedEvent if move_from.is_directory else FileMovedEvent 141 | self.queue_event(cls(src_path, dest_path)) 142 | self.queue_event(DirModifiedEvent(os.path.dirname(src_path))) 143 | self.queue_event(DirModifiedEvent(os.path.dirname(dest_path))) 144 | if move_from.is_directory and self.watch.is_recursive: 145 | for sub_event in generate_sub_moved_events(src_path, dest_path): 146 | self.queue_event(sub_event) 147 | return 148 | 149 | src_path = self._decode_path(event.src_path) 150 | if event.is_moved_to: 151 | cls = DirCreatedEvent if event.is_directory else FileCreatedEvent 152 | self.queue_event(cls(src_path)) 153 | self.queue_event(DirModifiedEvent(os.path.dirname(src_path))) 154 | if event.is_directory and self.watch.is_recursive: 155 | for sub_event in generate_sub_created_events(src_path): 156 | self.queue_event(sub_event) 157 | elif event.is_attrib: 158 | cls = DirModifiedEvent if event.is_directory else FileModifiedEvent 159 | self.queue_event(cls(src_path)) 160 | elif event.is_modify: 161 | cls = DirModifiedEvent if event.is_directory else FileModifiedEvent 162 | self.queue_event(cls(src_path)) 163 | elif event.is_delete_self: 164 | cls = DirDeletedEvent if event.is_directory else FileDeletedEvent 165 | self.queue_event(cls(src_path)) 166 | elif event.is_delete or event.is_moved_from: 167 | cls = DirDeletedEvent if event.is_directory else FileDeletedEvent 168 | self.queue_event(cls(src_path)) 169 | self.queue_event(DirModifiedEvent(os.path.dirname(src_path))) 170 | elif event.is_create: 171 | cls = DirCreatedEvent if event.is_directory else FileCreatedEvent 172 | self.queue_event(cls(src_path)) 173 | self.queue_event(DirModifiedEvent(os.path.dirname(src_path))) 174 | 175 | 176 | class InotifyObserver(BaseObserver): 177 | """ 178 | Observer thread that schedules watching directories and dispatches 179 | calls to event handlers. 180 | """ 181 | 182 | def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): 183 | BaseObserver.__init__(self, emitter_class=InotifyEmitter, 184 | timeout=timeout) 185 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/inotify_buffer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2014 Thomas Amland 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import time 18 | import logging 19 | import threading 20 | from collections import deque 21 | from watchdog.utils import DaemonThread 22 | from .inotify_c import Inotify 23 | 24 | STOP_EVENT = object() 25 | 26 | 27 | class _Worker(DaemonThread): 28 | """ 29 | Thread that reads events from `inotify` and writes to `queue`. 30 | """ 31 | 32 | def __init__(self, inotify, queue): 33 | DaemonThread.__init__(self) 34 | self._read_events = inotify.read_events 35 | self._queue = queue 36 | 37 | def run(self): 38 | while self.should_keep_running(): 39 | inotify_events = self._read_events() 40 | for inotify_event in inotify_events: 41 | logging.debug("worker: in event %s", inotify_event) 42 | if inotify_event.is_moved_to: 43 | from_event = self._queue._catch(inotify_event.cookie) 44 | if from_event: 45 | self._queue._put((from_event, inotify_event)) 46 | else: 47 | logging.debug("worker: could not find maching move_from event") 48 | self._queue._put(inotify_event) 49 | else: 50 | self._queue._put(inotify_event) 51 | 52 | 53 | class InotifyBuffer(object): 54 | """ 55 | A wrapper for `Inotify` that keeps events in memory for `delay` seconds. 56 | IN_MOVED_FROM and IN_MOVED_TO events are paired during this time. 57 | """ 58 | def __init__(self, path, recursive=False): 59 | self.delay = 0.5 60 | self._lock = threading.Lock() 61 | self._not_empty = threading.Condition(self._lock) 62 | self._queue = deque() 63 | self._inotify = Inotify(path, recursive) 64 | self._worker = _Worker(self._inotify, self) 65 | self._worker.start() 66 | 67 | def read_event(self): 68 | """ 69 | Returns a single event or a tuple of from/to events in case of a 70 | paired move event. 71 | """ 72 | while True: 73 | # wait for queue 74 | self._not_empty.acquire() 75 | while len(self._queue) == 0: 76 | self._not_empty.wait() 77 | head, insert_time = self._queue[0] 78 | self._not_empty.release() 79 | 80 | # wait for delay 81 | time_left = insert_time + self.delay - time.time() 82 | while time_left > 0: 83 | time.sleep(time_left) 84 | time_left = insert_time + self.delay - time.time() 85 | 86 | # return if event is still here 87 | self._lock.acquire() 88 | try: 89 | if len(self._queue) > 0 and self._queue[0][0] is head: 90 | self._queue.popleft() 91 | return head 92 | finally: 93 | self._lock.release() 94 | 95 | def close(self): 96 | self._worker.stop() 97 | self._inotify.close() 98 | self._worker.join() 99 | # Add the stop event to unblock the read_event which waits for 100 | # events in the queue... even after inotify buffer is closed. 101 | self._put(STOP_EVENT) 102 | 103 | def _put(self, elem): 104 | self._lock.acquire() 105 | self._queue.append((elem, time.time())) 106 | self._not_empty.notify() 107 | self._lock.release() 108 | 109 | def _catch(self, cookie): 110 | self._lock.acquire() 111 | ret = None 112 | for i, elem in enumerate(self._queue): 113 | event, _ = elem 114 | try: 115 | if event.is_moved_from and event.cookie == cookie: 116 | ret = event 117 | del self._queue[i] 118 | break 119 | except AttributeError: 120 | pass 121 | self._lock.release() 122 | return ret 123 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/polling.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | """ 21 | :module: watchdog.observers.polling 22 | :synopsis: Polling emitter implementation. 23 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 24 | 25 | Classes 26 | ------- 27 | .. autoclass:: PollingObserver 28 | :members: 29 | :show-inheritance: 30 | 31 | .. autoclass:: PollingObserverVFS 32 | :members: 33 | :show-inheritance: 34 | :special-members: 35 | """ 36 | 37 | from __future__ import with_statement 38 | import os 39 | import threading 40 | from functools import partial 41 | from watchdog.utils import stat as default_stat 42 | from watchdog.utils.dirsnapshot import DirectorySnapshot, DirectorySnapshotDiff 43 | from watchdog.observers.api import ( 44 | EventEmitter, 45 | BaseObserver, 46 | DEFAULT_OBSERVER_TIMEOUT, 47 | DEFAULT_EMITTER_TIMEOUT 48 | ) 49 | 50 | from watchdog.events import ( 51 | DirMovedEvent, 52 | DirDeletedEvent, 53 | DirCreatedEvent, 54 | DirModifiedEvent, 55 | FileMovedEvent, 56 | FileDeletedEvent, 57 | FileCreatedEvent, 58 | FileModifiedEvent 59 | ) 60 | 61 | 62 | class PollingEmitter(EventEmitter): 63 | """ 64 | Platform-independent emitter that polls a directory to detect file 65 | system changes. 66 | """ 67 | 68 | def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT, 69 | stat=default_stat, listdir=os.listdir): 70 | EventEmitter.__init__(self, event_queue, watch, timeout) 71 | self._snapshot = None 72 | self._lock = threading.Lock() 73 | self._take_snapshot = lambda: DirectorySnapshot( 74 | self.watch.path, self.watch.is_recursive, stat=stat, listdir=listdir) 75 | 76 | def queue_events(self, timeout): 77 | if not self._snapshot: 78 | self._snapshot = self._take_snapshot() 79 | 80 | # We don't want to hit the disk continuously. 81 | # timeout behaves like an interval for polling emitters. 82 | if self.stopped_event.wait(timeout): 83 | return 84 | 85 | with self._lock: 86 | if not self.should_keep_running(): 87 | return 88 | 89 | # Get event diff between fresh snapshot and previous snapshot. 90 | # Update snapshot. 91 | new_snapshot = self._take_snapshot() 92 | events = DirectorySnapshotDiff(self._snapshot, new_snapshot) 93 | self._snapshot = new_snapshot 94 | 95 | # Files. 96 | for src_path in events.files_deleted: 97 | self.queue_event(FileDeletedEvent(src_path)) 98 | for src_path in events.files_modified: 99 | self.queue_event(FileModifiedEvent(src_path)) 100 | for src_path in events.files_created: 101 | self.queue_event(FileCreatedEvent(src_path)) 102 | for src_path, dest_path in events.files_moved: 103 | self.queue_event(FileMovedEvent(src_path, dest_path)) 104 | 105 | # Directories. 106 | for src_path in events.dirs_deleted: 107 | self.queue_event(DirDeletedEvent(src_path)) 108 | for src_path in events.dirs_modified: 109 | self.queue_event(DirModifiedEvent(src_path)) 110 | for src_path in events.dirs_created: 111 | self.queue_event(DirCreatedEvent(src_path)) 112 | for src_path, dest_path in events.dirs_moved: 113 | self.queue_event(DirMovedEvent(src_path, dest_path)) 114 | 115 | 116 | class PollingObserver(BaseObserver): 117 | """ 118 | Platform-independent observer that polls a directory to detect file 119 | system changes. 120 | """ 121 | 122 | def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): 123 | BaseObserver.__init__(self, emitter_class=PollingEmitter, timeout=timeout) 124 | 125 | 126 | class PollingObserverVFS(BaseObserver): 127 | """ 128 | File system independent observer that polls a directory to detect changes. 129 | """ 130 | 131 | def __init__(self, stat, listdir, polling_interval=1): 132 | """ 133 | :param stat: stat function. See ``os.stat`` for details. 134 | :param listdir: listdir function. See ``os.listdir`` for details. 135 | :type polling_interval: float 136 | :param polling_interval: interval in seconds between polling the file system. 137 | """ 138 | emitter_cls = partial(PollingEmitter, stat=stat, listdir=listdir) 139 | BaseObserver.__init__(self, emitter_class=emitter_cls, timeout=polling_interval) 140 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/observers/read_directory_changes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # Copyright 2014 Thomas Amland 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | 20 | from __future__ import with_statement 21 | 22 | import ctypes 23 | import threading 24 | import os.path 25 | import time 26 | 27 | from watchdog.events import ( 28 | DirCreatedEvent, 29 | DirDeletedEvent, 30 | DirMovedEvent, 31 | DirModifiedEvent, 32 | FileCreatedEvent, 33 | FileDeletedEvent, 34 | FileMovedEvent, 35 | FileModifiedEvent, 36 | generate_sub_moved_events, 37 | generate_sub_created_events, 38 | ) 39 | 40 | from watchdog.observers.api import ( 41 | EventEmitter, 42 | BaseObserver, 43 | DEFAULT_OBSERVER_TIMEOUT, 44 | DEFAULT_EMITTER_TIMEOUT 45 | ) 46 | 47 | from watchdog.observers.winapi import ( 48 | read_events, 49 | get_directory_handle, 50 | close_directory_handle, 51 | ) 52 | 53 | 54 | # HACK: 55 | WATCHDOG_TRAVERSE_MOVED_DIR_DELAY = 1 # seconds 56 | 57 | 58 | class WindowsApiEmitter(EventEmitter): 59 | """ 60 | Windows API-based emitter that uses ReadDirectoryChangesW 61 | to detect file system changes for a watch. 62 | """ 63 | 64 | def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT): 65 | EventEmitter.__init__(self, event_queue, watch, timeout) 66 | self._lock = threading.Lock() 67 | self._handle = get_directory_handle(watch.path) 68 | 69 | def on_thread_stop(self): 70 | close_directory_handle(self._handle) 71 | 72 | def queue_events(self, timeout): 73 | winapi_events = read_events(self._handle, self.watch.is_recursive) 74 | with self._lock: 75 | last_renamed_src_path = "" 76 | for winapi_event in winapi_events: 77 | src_path = os.path.join(self.watch.path, winapi_event.src_path) 78 | 79 | if winapi_event.is_renamed_old: 80 | last_renamed_src_path = src_path 81 | elif winapi_event.is_renamed_new: 82 | dest_path = src_path 83 | src_path = last_renamed_src_path 84 | if os.path.isdir(dest_path): 85 | event = DirMovedEvent(src_path, dest_path) 86 | if self.watch.is_recursive: 87 | # HACK: We introduce a forced delay before 88 | # traversing the moved directory. This will read 89 | # only file movement that finishes within this 90 | # delay time. 91 | time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY) 92 | # The following block of code may not 93 | # obtain moved events for the entire tree if 94 | # the I/O is not completed within the above 95 | # delay time. So, it's not guaranteed to work. 96 | # TODO: Come up with a better solution, possibly 97 | # a way to wait for I/O to complete before 98 | # queuing events. 99 | for sub_moved_event in generate_sub_moved_events(src_path, dest_path): 100 | self.queue_event(sub_moved_event) 101 | self.queue_event(event) 102 | else: 103 | self.queue_event(FileMovedEvent(src_path, dest_path)) 104 | elif winapi_event.is_modified: 105 | cls = DirModifiedEvent if os.path.isdir(src_path) else FileModifiedEvent 106 | self.queue_event(cls(src_path)) 107 | elif winapi_event.is_added: 108 | isdir = os.path.isdir(src_path) 109 | cls = DirCreatedEvent if isdir else FileCreatedEvent 110 | self.queue_event(cls(src_path)) 111 | if isdir: 112 | # If a directory is moved from outside the watched folder to inside it 113 | # we only get a created directory event out of it, not any events for its children 114 | # so use the same hack as for file moves to get the child events 115 | time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY) 116 | sub_events = generate_sub_created_events(src_path) 117 | for sub_created_event in sub_events: 118 | self.queue_event(sub_created_event) 119 | elif winapi_event.is_removed: 120 | self.queue_event(FileDeletedEvent(src_path)) 121 | 122 | 123 | class WindowsApiObserver(BaseObserver): 124 | """ 125 | Observer thread that schedules watching directories and dispatches 126 | calls to event handlers. 127 | """ 128 | 129 | def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): 130 | BaseObserver.__init__(self, emitter_class=WindowsApiEmitter, 131 | timeout=timeout) 132 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/tricks/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | import os 21 | import signal 22 | import subprocess 23 | import time 24 | 25 | from watchdog.utils import echo, has_attribute 26 | from watchdog.events import PatternMatchingEventHandler 27 | 28 | 29 | class Trick(PatternMatchingEventHandler): 30 | 31 | """Your tricks should subclass this class.""" 32 | 33 | @classmethod 34 | def generate_yaml(cls): 35 | context = dict(module_name=cls.__module__, 36 | klass_name=cls.__name__) 37 | template_yaml = """- %(module_name)s.%(klass_name)s: 38 | args: 39 | - argument1 40 | - argument2 41 | kwargs: 42 | patterns: 43 | - "*.py" 44 | - "*.js" 45 | ignore_patterns: 46 | - "version.py" 47 | ignore_directories: false 48 | """ 49 | return template_yaml % context 50 | 51 | 52 | class LoggerTrick(Trick): 53 | 54 | """A simple trick that does only logs events.""" 55 | 56 | def on_any_event(self, event): 57 | pass 58 | 59 | @echo.echo 60 | def on_modified(self, event): 61 | pass 62 | 63 | @echo.echo 64 | def on_deleted(self, event): 65 | pass 66 | 67 | @echo.echo 68 | def on_created(self, event): 69 | pass 70 | 71 | @echo.echo 72 | def on_moved(self, event): 73 | pass 74 | 75 | 76 | class ShellCommandTrick(Trick): 77 | 78 | """Executes shell commands in response to matched events.""" 79 | 80 | def __init__(self, shell_command=None, patterns=None, ignore_patterns=None, 81 | ignore_directories=False, wait_for_process=False, 82 | drop_during_process=False): 83 | super(ShellCommandTrick, self).__init__(patterns, ignore_patterns, 84 | ignore_directories) 85 | self.shell_command = shell_command 86 | self.wait_for_process = wait_for_process 87 | self.drop_during_process = drop_during_process 88 | self.process = None 89 | 90 | def on_any_event(self, event): 91 | from string import Template 92 | 93 | if self.drop_during_process and self.process and self.process.poll() is None: 94 | return 95 | 96 | if event.is_directory: 97 | object_type = 'directory' 98 | else: 99 | object_type = 'file' 100 | 101 | context = { 102 | 'watch_src_path': event.src_path, 103 | 'watch_dest_path': '', 104 | 'watch_event_type': event.event_type, 105 | 'watch_object': object_type, 106 | } 107 | 108 | if self.shell_command is None: 109 | if has_attribute(event, 'dest_path'): 110 | context.update({'dest_path': event.dest_path}) 111 | command = 'echo "${watch_event_type} ${watch_object} from ${watch_src_path} to ${watch_dest_path}"' 112 | else: 113 | command = 'echo "${watch_event_type} ${watch_object} ${watch_src_path}"' 114 | else: 115 | if has_attribute(event, 'dest_path'): 116 | context.update({'watch_dest_path': event.dest_path}) 117 | command = self.shell_command 118 | 119 | command = Template(command).safe_substitute(**context) 120 | self.process = subprocess.Popen(command, shell=True) 121 | if self.wait_for_process: 122 | self.process.wait() 123 | 124 | 125 | class AutoRestartTrick(Trick): 126 | 127 | """Starts a long-running subprocess and restarts it on matched events. 128 | 129 | The command parameter is a list of command arguments, such as 130 | ['bin/myserver', '-c', 'etc/myconfig.ini']. 131 | 132 | Call start() after creating the Trick. Call stop() when stopping 133 | the process. 134 | """ 135 | 136 | def __init__(self, command, patterns=None, ignore_patterns=None, 137 | ignore_directories=False, stop_signal=signal.SIGINT, 138 | kill_after=10): 139 | super(AutoRestartTrick, self).__init__( 140 | patterns, ignore_patterns, ignore_directories) 141 | self.command = ['setsid'] + command 142 | self.stop_signal = stop_signal 143 | self.kill_after = kill_after 144 | self.process = None 145 | 146 | def start(self): 147 | self.process = subprocess.Popen(self.command) 148 | 149 | def stop(self): 150 | if self.process is None: 151 | return 152 | try: 153 | os.killpg(os.getpgid(self.process.pid), self.stop_signal) 154 | except OSError: 155 | # Process is already gone 156 | pass 157 | else: 158 | kill_time = time.time() + self.kill_after 159 | while time.time() < kill_time: 160 | if self.process.poll() is not None: 161 | break 162 | time.sleep(0.25) 163 | else: 164 | try: 165 | os.killpg(os.getpgid(self.process.pid), 9) 166 | except OSError: 167 | # Process is already gone 168 | pass 169 | self.process = None 170 | 171 | @echo.echo 172 | def on_any_event(self, event): 173 | self.stop() 174 | self.start() 175 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | """ 21 | :module: watchdog.utils 22 | :synopsis: Utility classes and functions. 23 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 24 | 25 | Classes 26 | ------- 27 | .. autoclass:: DaemonThread 28 | :members: 29 | :show-inheritance: 30 | :inherited-members: 31 | 32 | """ 33 | import os 34 | import sys 35 | import threading 36 | import watchdog.utils.platform 37 | from collections import namedtuple 38 | 39 | 40 | if sys.version_info[0] == 2 and platform.is_windows(): 41 | # st_ino is not implemented in os.stat on this platform 42 | import win32stat 43 | stat = win32stat.stat 44 | else: 45 | stat = os.stat 46 | 47 | 48 | def ctypes_find_library(name, default): 49 | """Finds a dynamic library.""" 50 | try: 51 | import ctypes.util 52 | except ImportError: 53 | raise RuntimeError('ctypes not available on this system') 54 | module_path = None 55 | try: 56 | module_path = ctypes.util.find_library(name) 57 | except (OSError, IOError): 58 | module_path = default 59 | return module_path 60 | 61 | 62 | def has_attribute(ob, attribute): 63 | """ 64 | :func:`hasattr` swallows exceptions. :func:`has_attribute` tests a Python object for the 65 | presence of an attribute. 66 | 67 | :param ob: 68 | object to inspect 69 | :param attribute: 70 | ``str`` for the name of the attribute. 71 | """ 72 | return getattr(ob, attribute, None) is not None 73 | 74 | 75 | class DaemonThread(threading.Thread): 76 | 77 | """ 78 | Daemon thread convenience class, sets a few properties and makes 79 | writing daemon threads a little easier. 80 | """ 81 | 82 | def __init__(self): 83 | threading.Thread.__init__(self) 84 | if has_attribute(self, 'daemon'): 85 | self.daemon = True 86 | else: 87 | self.setDaemon(True) 88 | self._stopped_event = threading.Event() 89 | 90 | if not has_attribute(self._stopped_event, 'is_set'): 91 | self._stopped_event.is_set = self._stopped_event.isSet 92 | 93 | @property 94 | def stopped_event(self): 95 | return self._stopped_event 96 | 97 | def should_keep_running(self): 98 | """Determines whether the daemon thread should continue running.""" 99 | return not self._stopped_event.is_set() 100 | 101 | def on_thread_stop(self): 102 | """Override this method instead of :meth:`stop()`. 103 | :meth:`stop()` calls this method. 104 | 105 | Note that this method is called immediately after the daemon thread 106 | is signaled to halt. 107 | """ 108 | pass 109 | 110 | def stop(self): 111 | """Signals the daemon thread to stop.""" 112 | self._stopped_event.set() 113 | self.on_thread_stop() 114 | 115 | 116 | def load_module(module_name): 117 | """Imports a module given its name and returns a handle to it.""" 118 | try: 119 | __import__(module_name) 120 | except ImportError: 121 | raise ImportError('No module named %s' % module_name) 122 | return sys.modules[module_name] 123 | 124 | 125 | def load_class(dotted_path): 126 | """Loads and returns a class definition provided a dotted path 127 | specification the last part of the dotted path is the class name 128 | and there is at least one module name preceding the class name. 129 | 130 | Notes: 131 | You will need to ensure that the module you are trying to load 132 | exists in the Python path. 133 | 134 | Examples: 135 | - module.name.ClassName # Provided module.name is in the Python path. 136 | - module.ClassName # Provided module is in the Python path. 137 | 138 | What won't work: 139 | - ClassName 140 | - modle.name.ClassName # Typo in module name. 141 | - module.name.ClasNam # Typo in classname. 142 | """ 143 | dotted_path_split = dotted_path.split('.') 144 | if len(dotted_path_split) > 1: 145 | klass_name = dotted_path_split[-1] 146 | module_name = '.'.join(dotted_path_split[:-1]) 147 | 148 | module = load_module(module_name) 149 | if has_attribute(module, klass_name): 150 | klass = getattr(module, klass_name) 151 | return klass 152 | # Finally create and return an instance of the class 153 | # return klass(*args, **kwargs) 154 | else: 155 | raise AttributeError('Module %s does not have class attribute %s' % ( 156 | module_name, klass_name)) 157 | else: 158 | raise ValueError( 159 | 'Dotted module path %s must contain a module name and a classname' % dotted_path) 160 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/bricks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | """ 21 | Utility collections or "bricks". 22 | 23 | :module: watchdog.utils.bricks 24 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 25 | :author: lalinsky@gmail.com (Lukáš Lalinský) 26 | :author: python@rcn.com (Raymond Hettinger) 27 | 28 | Classes 29 | ======= 30 | .. autoclass:: OrderedSetQueue 31 | :members: 32 | :show-inheritance: 33 | :inherited-members: 34 | 35 | .. autoclass:: OrderedSet 36 | 37 | """ 38 | 39 | import sys 40 | import collections 41 | from .compat import queue 42 | 43 | class SkipRepeatsQueue(queue.Queue): 44 | 45 | """Thread-safe implementation of an special queue where a 46 | put of the last-item put'd will be dropped. 47 | 48 | The implementation leverages locking already implemented in the base class 49 | redefining only the primitives. 50 | 51 | Queued items must be immutable and hashable so that they can be used 52 | as dictionary keys. You must implement **only read-only properties** and 53 | the :meth:`Item.__hash__()`, :meth:`Item.__eq__()`, and 54 | :meth:`Item.__ne__()` methods for items to be hashable. 55 | 56 | An example implementation follows:: 57 | 58 | class Item(object): 59 | def __init__(self, a, b): 60 | self._a = a 61 | self._b = b 62 | 63 | @property 64 | def a(self): 65 | return self._a 66 | 67 | @property 68 | def b(self): 69 | return self._b 70 | 71 | def _key(self): 72 | return (self._a, self._b) 73 | 74 | def __eq__(self, item): 75 | return self._key() == item._key() 76 | 77 | def __ne__(self, item): 78 | return self._key() != item._key() 79 | 80 | def __hash__(self): 81 | return hash(self._key()) 82 | 83 | based on the OrderedSetQueue below 84 | """ 85 | 86 | def _init(self, maxsize): 87 | queue.Queue._init(self, maxsize) 88 | self._last_item = None 89 | 90 | def _put(self, item): 91 | if item != self._last_item: 92 | queue.Queue._put(self, item) 93 | self._last_item = item 94 | else: 95 | # `put` increments `unfinished_tasks` even if we did not put 96 | # anything into the queue here 97 | self.unfinished_tasks -= 1 98 | 99 | def _get(self): 100 | item = queue.Queue._get(self) 101 | if item is self._last_item: 102 | self._last_item = None 103 | return item 104 | 105 | 106 | class OrderedSetQueue(queue.Queue): 107 | 108 | """Thread-safe implementation of an ordered set queue. 109 | 110 | Disallows adding a duplicate item while maintaining the 111 | order of items in the queue. The implementation leverages 112 | locking already implemented in the base class 113 | redefining only the primitives. Since the internal queue 114 | is not replaced, the order is maintained. The set is used 115 | merely to check for the existence of an item. 116 | 117 | Queued items must be immutable and hashable so that they can be used 118 | as dictionary keys. You must implement **only read-only properties** and 119 | the :meth:`Item.__hash__()`, :meth:`Item.__eq__()`, and 120 | :meth:`Item.__ne__()` methods for items to be hashable. 121 | 122 | An example implementation follows:: 123 | 124 | class Item(object): 125 | def __init__(self, a, b): 126 | self._a = a 127 | self._b = b 128 | 129 | @property 130 | def a(self): 131 | return self._a 132 | 133 | @property 134 | def b(self): 135 | return self._b 136 | 137 | def _key(self): 138 | return (self._a, self._b) 139 | 140 | def __eq__(self, item): 141 | return self._key() == item._key() 142 | 143 | def __ne__(self, item): 144 | return self._key() != item._key() 145 | 146 | def __hash__(self): 147 | return hash(self._key()) 148 | 149 | :author: lalinsky@gmail.com (Lukáš Lalinský) 150 | :url: http://stackoverflow.com/questions/1581895/how-check-if-a-task-is-already-in-python-queue 151 | """ 152 | 153 | def _init(self, maxsize): 154 | queue.Queue._init(self, maxsize) 155 | self._set_of_items = set() 156 | 157 | def _put(self, item): 158 | if item not in self._set_of_items: 159 | queue.Queue._put(self, item) 160 | self._set_of_items.add(item) 161 | else: 162 | # `put` increments `unfinished_tasks` even if we did not put 163 | # anything into the queue here 164 | self.unfinished_tasks -= 1 165 | 166 | def _get(self): 167 | item = queue.Queue._get(self) 168 | self._set_of_items.remove(item) 169 | return item 170 | 171 | 172 | if sys.version_info >= (2, 6, 0): 173 | KEY, PREV, NEXT = list(range(3)) 174 | 175 | class OrderedSet(collections.MutableSet): 176 | 177 | """ 178 | Implementation based on a doubly-linked link and an internal dictionary. 179 | This design gives :class:`OrderedSet` the same big-Oh running times as 180 | regular sets including O(1) adds, removes, and lookups as well as 181 | O(n) iteration. 182 | 183 | .. ADMONITION:: Implementation notes 184 | 185 | Runs on Python 2.6 or later (and runs on Python 3.0 or later 186 | without any modifications). 187 | 188 | :author: python@rcn.com (Raymond Hettinger) 189 | :url: http://code.activestate.com/recipes/576694/ 190 | """ 191 | 192 | def __init__(self, iterable=None): 193 | self.end = end = [] 194 | end += [None, end, end] # sentinel node for doubly linked list 195 | self.map = {} # key --> [key, prev, next] 196 | if iterable is not None: 197 | self |= iterable 198 | 199 | def __len__(self): 200 | return len(self.map) 201 | 202 | def __contains__(self, key): 203 | return key in self.map 204 | 205 | def add(self, key): 206 | if key not in self.map: 207 | end = self.end 208 | curr = end[PREV] 209 | curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end] 210 | 211 | def discard(self, key): 212 | if key in self.map: 213 | key, prev, _next = self.map.pop(key) 214 | prev[NEXT] = _next 215 | _next[PREV] = prev 216 | 217 | def __iter__(self): 218 | end = self.end 219 | curr = end[NEXT] 220 | while curr is not end: 221 | yield curr[KEY] 222 | curr = curr[NEXT] 223 | 224 | def __reversed__(self): 225 | end = self.end 226 | curr = end[PREV] 227 | while curr is not end: 228 | yield curr[KEY] 229 | curr = curr[PREV] 230 | 231 | def pop(self, last=True): 232 | if not self: 233 | raise KeyError('set is empty') 234 | key = next(reversed(self)) if last else next(iter(self)) 235 | self.discard(key) 236 | return key 237 | 238 | def __repr__(self): 239 | if not self: 240 | return '%s()' % (self.__class__.__name__,) 241 | return '%s(%r)' % (self.__class__.__name__, list(self)) 242 | 243 | def __eq__(self, other): 244 | if isinstance(other, OrderedSet): 245 | return len(self) == len(other) and list(self) == list(other) 246 | return set(self) == set(other) 247 | 248 | def __del__(self): 249 | self.clear() # remove circular references 250 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2014 Thomas Amland 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | try: 18 | import queue 19 | except ImportError: 20 | import Queue as queue 21 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/decorators.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Most of this code was obtained from the Python documentation online. 4 | 5 | """Decorator utility functions. 6 | 7 | decorators: 8 | - synchronized 9 | - propertyx 10 | - accepts 11 | - returns 12 | - singleton 13 | - attrs 14 | - deprecated 15 | """ 16 | 17 | import functools 18 | import warnings 19 | import threading 20 | import sys 21 | 22 | 23 | def synchronized(lock=None): 24 | """Decorator that synchronizes a method or a function with a mutex lock. 25 | 26 | Example usage: 27 | 28 | @synchronized() 29 | def operation(self, a, b): 30 | ... 31 | """ 32 | if lock is None: 33 | lock = threading.Lock() 34 | 35 | def wrapper(function): 36 | def new_function(*args, **kwargs): 37 | lock.acquire() 38 | try: 39 | return function(*args, **kwargs) 40 | finally: 41 | lock.release() 42 | 43 | return new_function 44 | 45 | return wrapper 46 | 47 | 48 | def propertyx(function): 49 | """Decorator to easily create properties in classes. 50 | 51 | Example: 52 | 53 | class Angle(object): 54 | def __init__(self, rad): 55 | self._rad = rad 56 | 57 | @property 58 | def rad(): 59 | def fget(self): 60 | return self._rad 61 | def fset(self, angle): 62 | if isinstance(angle, Angle): 63 | angle = angle.rad 64 | self._rad = float(angle) 65 | 66 | Arguments: 67 | - `function`: The function to be decorated. 68 | """ 69 | keys = ('fget', 'fset', 'fdel') 70 | func_locals = {'doc': function.__doc__} 71 | 72 | def probe_func(frame, event, arg): 73 | if event == 'return': 74 | locals = frame.f_locals 75 | func_locals.update(dict((k, locals.get(k)) for k in keys)) 76 | sys.settrace(None) 77 | return probe_func 78 | 79 | sys.settrace(probe_func) 80 | function() 81 | return property(**func_locals) 82 | 83 | 84 | def accepts(*types): 85 | """Decorator to ensure that the decorated function accepts the given types as arguments. 86 | 87 | Example: 88 | @accepts(int, (int,float)) 89 | @returns((int,float)) 90 | def func(arg1, arg2): 91 | return arg1 * arg2 92 | """ 93 | 94 | def check_accepts(f): 95 | assert len(types) == f.__code__.co_argcount 96 | 97 | def new_f(*args, **kwds): 98 | for (a, t) in zip(args, types): 99 | assert isinstance(a, t),\ 100 | "arg %r does not match %s" % (a, t) 101 | return f(*args, **kwds) 102 | 103 | new_f.__name__ = f.__name__ 104 | return new_f 105 | 106 | return check_accepts 107 | 108 | 109 | def returns(rtype): 110 | """Decorator to ensure that the decorated function returns the given 111 | type as argument. 112 | 113 | Example: 114 | @accepts(int, (int,float)) 115 | @returns((int,float)) 116 | def func(arg1, arg2): 117 | return arg1 * arg2 118 | """ 119 | 120 | def check_returns(f): 121 | def new_f(*args, **kwds): 122 | result = f(*args, **kwds) 123 | assert isinstance(result, rtype),\ 124 | "return value %r does not match %s" % (result, rtype) 125 | return result 126 | 127 | new_f.__name__ = f.__name__ 128 | return new_f 129 | 130 | return check_returns 131 | 132 | 133 | def singleton(cls): 134 | """Decorator to ensures a class follows the singleton pattern. 135 | 136 | Example: 137 | @singleton 138 | class MyClass: 139 | ... 140 | """ 141 | instances = {} 142 | 143 | def getinstance(): 144 | if cls not in instances: 145 | instances[cls] = cls() 146 | return instances[cls] 147 | 148 | return getinstance 149 | 150 | 151 | def attrs(**kwds): 152 | """Decorator to add attributes to a function. 153 | 154 | Example: 155 | 156 | @attrs(versionadded="2.2", 157 | author="Guido van Rossum") 158 | def mymethod(f): 159 | ... 160 | """ 161 | 162 | def decorate(f): 163 | for k in kwds: 164 | setattr(f, k, kwds[k]) 165 | return f 166 | 167 | return decorate 168 | 169 | 170 | def deprecated(func): 171 | """This is a decorator which can be used to mark functions 172 | as deprecated. It will result in a warning being emitted 173 | when the function is used. 174 | 175 | ## Usage examples ## 176 | @deprecated 177 | def my_func(): 178 | pass 179 | 180 | @other_decorators_must_be_upper 181 | @deprecated 182 | def my_func(): 183 | pass 184 | """ 185 | 186 | @functools.wraps(func) 187 | def new_func(*args, **kwargs): 188 | warnings.warn_explicit( 189 | "Call to deprecated function %(funcname)s." % { 190 | 'funcname': func.__name__, 191 | }, 192 | category=DeprecationWarning, 193 | filename=func.__code__.co_filename, 194 | lineno=func.__code__.co_firstlineno + 1 195 | ) 196 | return func(*args, **kwargs) 197 | 198 | return new_func 199 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/dirsnapshot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # Copyright 2014 Thomas Amland 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | 20 | """ 21 | :module: watchdog.utils.dirsnapshot 22 | :synopsis: Directory snapshots and comparison. 23 | :author: yesudeep@google.com (Yesudeep Mangalapilly) 24 | 25 | .. ADMONITION:: Where are the moved events? They "disappeared" 26 | 27 | This implementation does not take partition boundaries 28 | into consideration. It will only work when the directory 29 | tree is entirely on the same file system. More specifically, 30 | any part of the code that depends on inode numbers can 31 | break if partition boundaries are crossed. In these cases, 32 | the snapshot diff will represent file/directory movement as 33 | created and deleted events. 34 | 35 | Classes 36 | ------- 37 | .. autoclass:: DirectorySnapshot 38 | :members: 39 | :show-inheritance: 40 | 41 | .. autoclass:: DirectorySnapshotDiff 42 | :members: 43 | :show-inheritance: 44 | 45 | """ 46 | 47 | import os 48 | from stat import S_ISDIR 49 | from watchdog.utils import platform 50 | from watchdog.utils import stat as default_stat 51 | 52 | 53 | class DirectorySnapshotDiff(object): 54 | """ 55 | Compares two directory snapshots and creates an object that represents 56 | the difference between the two snapshots. 57 | 58 | :param ref: 59 | The reference directory snapshot. 60 | :type ref: 61 | :class:`DirectorySnapshot` 62 | :param snapshot: 63 | The directory snapshot which will be compared 64 | with the reference snapshot. 65 | :type snapshot: 66 | :class:`DirectorySnapshot` 67 | """ 68 | 69 | def __init__(self, ref, snapshot): 70 | created = snapshot.paths - ref.paths 71 | deleted = ref.paths - snapshot.paths 72 | 73 | # check that all unchanged paths have the same inode 74 | for path in ref.paths & snapshot.paths: 75 | if ref.inode(path) != snapshot.inode(path): 76 | created.add(path) 77 | deleted.add(path) 78 | 79 | # find moved paths 80 | moved = set() 81 | for path in set(deleted): 82 | inode = ref.inode(path) 83 | new_path = snapshot.path(inode) 84 | if new_path: 85 | # file is not deleted but moved 86 | deleted.remove(path) 87 | moved.add((path, new_path)) 88 | 89 | for path in set(created): 90 | inode = snapshot.inode(path) 91 | old_path = ref.path(inode) 92 | if old_path: 93 | created.remove(path) 94 | moved.add((old_path, path)) 95 | 96 | # find modified paths 97 | # first check paths that have not moved 98 | modified = set() 99 | for path in ref.paths & snapshot.paths: 100 | if ref.inode(path) == snapshot.inode(path): 101 | if ref.mtime(path) != snapshot.mtime(path): 102 | modified.add(path) 103 | 104 | for (old_path, new_path) in moved: 105 | if ref.mtime(old_path) != snapshot.mtime(new_path): 106 | modified.add(old_path) 107 | 108 | self._dirs_created = [path for path in created if snapshot.isdir(path)] 109 | self._dirs_deleted = [path for path in deleted if ref.isdir(path)] 110 | self._dirs_modified = [path for path in modified if ref.isdir(path)] 111 | self._dirs_moved = [(frm, to) for (frm, to) in moved if ref.isdir(frm)] 112 | 113 | self._files_created = list(created - set(self._dirs_created)) 114 | self._files_deleted = list(deleted - set(self._dirs_deleted)) 115 | self._files_modified = list(modified - set(self._dirs_modified)) 116 | self._files_moved = list(moved - set(self._dirs_moved)) 117 | 118 | @property 119 | def files_created(self): 120 | """List of files that were created.""" 121 | return self._files_created 122 | 123 | @property 124 | def files_deleted(self): 125 | """List of files that were deleted.""" 126 | return self._files_deleted 127 | 128 | @property 129 | def files_modified(self): 130 | """List of files that were modified.""" 131 | return self._files_modified 132 | 133 | @property 134 | def files_moved(self): 135 | """ 136 | List of files that were moved. 137 | 138 | Each event is a two-tuple the first item of which is the path 139 | that has been renamed to the second item in the tuple. 140 | """ 141 | return self._files_moved 142 | 143 | @property 144 | def dirs_modified(self): 145 | """ 146 | List of directories that were modified. 147 | """ 148 | return self._dirs_modified 149 | 150 | @property 151 | def dirs_moved(self): 152 | """ 153 | List of directories that were moved. 154 | 155 | Each event is a two-tuple the first item of which is the path 156 | that has been renamed to the second item in the tuple. 157 | """ 158 | return self._dirs_moved 159 | 160 | @property 161 | def dirs_deleted(self): 162 | """ 163 | List of directories that were deleted. 164 | """ 165 | return self._dirs_deleted 166 | 167 | @property 168 | def dirs_created(self): 169 | """ 170 | List of directories that were created. 171 | """ 172 | return self._dirs_created 173 | 174 | class DirectorySnapshot(object): 175 | """ 176 | A snapshot of stat information of files in a directory. 177 | 178 | :param path: 179 | The directory path for which a snapshot should be taken. 180 | :type path: 181 | ``str`` 182 | :param recursive: 183 | ``True`` if the entire directory tree should be included in the 184 | snapshot; ``False`` otherwise. 185 | :type recursive: 186 | ``bool`` 187 | :param walker_callback: 188 | .. deprecated:: 0.7.2 189 | :param stat: 190 | Use custom stat function that returns a stat structure for path. 191 | Currently only st_dev, st_ino, st_mode and st_mtime are needed. 192 | 193 | A function with the signature ``walker_callback(path, stat_info)`` 194 | which will be called for every entry in the directory tree. 195 | :param listdir: 196 | Use custom listdir function. See ``os.listdir`` for details. 197 | """ 198 | 199 | def __init__(self, path, recursive=True, 200 | walker_callback=(lambda p, s: None), 201 | stat=default_stat, 202 | listdir=os.listdir): 203 | self._stat_info = {} 204 | self._inode_to_path = {} 205 | 206 | st = stat(path) 207 | self._stat_info[path] = st 208 | self._inode_to_path[(st.st_ino, st.st_dev)] = path 209 | 210 | def walk(root): 211 | paths = [os.path.join(root, name) for name in listdir(root)] 212 | entries = [] 213 | for p in paths: 214 | try: 215 | entries.append((p, stat(p))) 216 | except OSError: 217 | continue 218 | for _ in entries: 219 | yield _ 220 | if recursive: 221 | for path, st in entries: 222 | if S_ISDIR(st.st_mode): 223 | for _ in walk(path): 224 | yield _ 225 | 226 | for p, st in walk(path): 227 | i = (st.st_ino, st.st_dev) 228 | self._inode_to_path[i] = p 229 | self._stat_info[p] = st 230 | walker_callback(p, st) 231 | 232 | @property 233 | def paths(self): 234 | """ 235 | Set of file/directory paths in the snapshot. 236 | """ 237 | return set(self._stat_info.keys()) 238 | 239 | def path(self, id): 240 | """ 241 | Returns path for id. None if id is unknown to this snapshot. 242 | """ 243 | return self._inode_to_path.get(id) 244 | 245 | def inode(self, path): 246 | """ Returns an id for path. """ 247 | st = self._stat_info[path] 248 | return (st.st_ino, st.st_dev) 249 | 250 | def isdir(self, path): 251 | return S_ISDIR(self._stat_info[path].st_mode) 252 | 253 | def mtime(self, path): 254 | return self._stat_info[path].st_mtime 255 | 256 | def stat_info(self, path): 257 | """ 258 | Returns a stat information object for the specified path from 259 | the snapshot. 260 | 261 | Attached information is subject to change. Do not use unless 262 | you specify `stat` in constructor. Use :func:`inode`, :func:`mtime`, 263 | :func:`isdir` instead. 264 | 265 | :param path: 266 | The path for which stat information should be obtained 267 | from a snapshot. 268 | """ 269 | return self._stat_info[path] 270 | 271 | def __sub__(self, previous_dirsnap): 272 | """Allow subtracting a DirectorySnapshot object instance from 273 | another. 274 | 275 | :returns: 276 | A :class:`DirectorySnapshotDiff` object. 277 | """ 278 | return DirectorySnapshotDiff(previous_dirsnap, self) 279 | 280 | def __str__(self): 281 | return self.__repr__() 282 | 283 | def __repr__(self): 284 | return str(self._stat_info) 285 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/echo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # echo.py: Tracing function calls using Python decorators. 4 | # 5 | # Written by Thomas Guest 6 | # Please see http://wordaligned.org/articles/echo 7 | # 8 | # Place into the public domain. 9 | 10 | """ Echo calls made to functions and methods in a module. 11 | 12 | "Echoing" a function call means printing out the name of the function 13 | and the values of its arguments before making the call (which is more 14 | commonly referred to as "tracing", but Python already has a trace module). 15 | 16 | Example: to echo calls made to functions in "my_module" do: 17 | 18 | import echo 19 | import my_module 20 | echo.echo_module(my_module) 21 | 22 | Example: to echo calls made to functions in "my_module.my_class" do: 23 | 24 | echo.echo_class(my_module.my_class) 25 | 26 | Alternatively, echo.echo can be used to decorate functions. Calls to the 27 | decorated function will be echoed. 28 | 29 | Example: 30 | 31 | @echo.echo 32 | def my_function(args): 33 | pass 34 | """ 35 | import inspect 36 | import sys 37 | 38 | 39 | def name(item): 40 | " Return an item's name. " 41 | return item.__name__ 42 | 43 | 44 | def is_classmethod(instancemethod): 45 | " Determine if an instancemethod is a classmethod. " 46 | return instancemethod.__self__ is not None 47 | 48 | 49 | def is_class_private_name(name): 50 | " Determine if a name is a class private name. " 51 | # Exclude system defined names such as __init__, __add__ etc 52 | return name.startswith("__") and not name.endswith("__") 53 | 54 | 55 | def method_name(method): 56 | """ Return a method's name. 57 | 58 | This function returns the name the method is accessed by from 59 | outside the class (i.e. it prefixes "private" methods appropriately). 60 | """ 61 | mname = name(method) 62 | if is_class_private_name(mname): 63 | mname = "_%s%s" % (name(method.__self__.__class__), mname) 64 | return mname 65 | 66 | 67 | def format_arg_value(arg_val): 68 | """ Return a string representing a (name, value) pair. 69 | 70 | >>> format_arg_value(('x', (1, 2, 3))) 71 | 'x=(1, 2, 3)' 72 | """ 73 | arg, val = arg_val 74 | return "%s=%r" % (arg, val) 75 | 76 | 77 | def echo(fn, write=sys.stdout.write): 78 | """ Echo calls to a function. 79 | 80 | Returns a decorated version of the input function which "echoes" calls 81 | made to it by writing out the function's name and the arguments it was 82 | called with. 83 | """ 84 | import functools 85 | # Unpack function's arg count, arg names, arg defaults 86 | code = fn.__code__ 87 | argcount = code.co_argcount 88 | argnames = code.co_varnames[:argcount] 89 | fn_defaults = fn.__defaults__ or list() 90 | argdefs = dict(list(zip(argnames[-len(fn_defaults):], fn_defaults))) 91 | 92 | @functools.wraps(fn) 93 | def wrapped(*v, **k): 94 | # Collect function arguments by chaining together positional, 95 | # defaulted, extra positional and keyword arguments. 96 | positional = list(map(format_arg_value, list(zip(argnames, v)))) 97 | defaulted = [format_arg_value((a, argdefs[a])) 98 | for a in argnames[len(v):] if a not in k] 99 | nameless = list(map(repr, v[argcount:])) 100 | keyword = list(map(format_arg_value, list(k.items()))) 101 | args = positional + defaulted + nameless + keyword 102 | write("%s(%s)\n" % (name(fn), ", ".join(args))) 103 | return fn(*v, **k) 104 | 105 | return wrapped 106 | 107 | 108 | def echo_instancemethod(klass, method, write=sys.stdout.write): 109 | """ Change an instancemethod so that calls to it are echoed. 110 | 111 | Replacing a classmethod is a little more tricky. 112 | See: http://www.python.org/doc/current/ref/types.html 113 | """ 114 | mname = method_name(method) 115 | never_echo = "__str__", "__repr__", # Avoid recursion printing method calls 116 | if mname in never_echo: 117 | pass 118 | elif is_classmethod(method): 119 | setattr(klass, mname, classmethod(echo(method.__func__, write))) 120 | else: 121 | setattr(klass, mname, echo(method, write)) 122 | 123 | 124 | def echo_class(klass, write=sys.stdout.write): 125 | """ Echo calls to class methods and static functions 126 | """ 127 | for _, method in inspect.getmembers(klass, inspect.ismethod): 128 | echo_instancemethod(klass, method, write) 129 | for _, fn in inspect.getmembers(klass, inspect.isfunction): 130 | setattr(klass, name(fn), staticmethod(echo(fn, write))) 131 | 132 | 133 | def echo_module(mod, write=sys.stdout.write): 134 | """ Echo calls to functions and methods in a module. 135 | """ 136 | for fname, fn in inspect.getmembers(mod, inspect.isfunction): 137 | setattr(mod, fname, echo(fn, write)) 138 | for _, klass in inspect.getmembers(mod, inspect.isclass): 139 | echo_class(klass, write) 140 | 141 | if __name__ == "__main__": 142 | import doctest 143 | 144 | optionflags = doctest.ELLIPSIS 145 | doctest.testfile('echoexample.txt', optionflags=optionflags) 146 | doctest.testmod(optionflags=optionflags) 147 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/importlib2.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2013 Peter M. Elias 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 all 13 | # 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 THE 21 | # SOFTWARE 22 | 23 | 24 | def import_module(target, relative_to=None): 25 | target_parts = target.split('.') 26 | target_depth = target_parts.count('') 27 | target_path = target_parts[target_depth:] 28 | target = target[target_depth:] 29 | fromlist = [target] 30 | if target_depth and relative_to: 31 | relative_parts = relative_to.split('.') 32 | relative_to = '.'.join(relative_parts[:-(target_depth - 1) or None]) 33 | if len(target_path) > 1: 34 | relative_to = '.'.join(filter(None, [relative_to]) + target_path[:-1]) 35 | fromlist = target_path[-1:] 36 | target = fromlist[0] 37 | elif not relative_to: 38 | fromlist = [] 39 | mod = __import__(relative_to or target, globals(), locals(), fromlist) 40 | return getattr(mod, target, mod) 41 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/platform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | import sys 21 | 22 | PLATFORM_WINDOWS = 'windows' 23 | PLATFORM_LINUX = 'linux' 24 | PLATFORM_BSD = 'bsd' 25 | PLATFORM_DARWIN = 'darwin' 26 | PLATFORM_UNKNOWN = 'unknown' 27 | 28 | 29 | def get_platform_name(): 30 | if sys.platform.startswith("win"): 31 | return PLATFORM_WINDOWS 32 | elif sys.platform.startswith('darwin'): 33 | return PLATFORM_DARWIN 34 | elif sys.platform.startswith('linux'): 35 | return PLATFORM_LINUX 36 | elif sys.platform.startswith('bsd'): 37 | return PLATFORM_BSD 38 | else: 39 | return PLATFORM_UNKNOWN 40 | 41 | __platform__ = get_platform_name() 42 | 43 | 44 | def is_linux(): 45 | return __platform__ == PLATFORM_LINUX 46 | 47 | 48 | def is_bsd(): 49 | return __platform__ == PLATFORM_BSD 50 | 51 | 52 | def is_darwin(): 53 | return __platform__ == PLATFORM_DARWIN 54 | 55 | 56 | def is_windows(): 57 | return __platform__ == PLATFORM_WINDOWS 58 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/unicode_paths.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2013 Will Bond 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | 24 | 25 | import sys 26 | 27 | from watchdog.utils import platform 28 | 29 | try: 30 | # Python 2 31 | str_cls = unicode 32 | bytes_cls = str 33 | except NameError: 34 | # Python 3 35 | str_cls = str 36 | bytes_cls = bytes 37 | 38 | 39 | fs_encoding = sys.getfilesystemencoding() 40 | # This is used by Linux when the locale seems to be improperly set. UTF-8 tends 41 | # to be the encoding used by all distros, so this is a good fallback. 42 | fs_fallback_encoding = 'utf-8' 43 | 44 | 45 | def encode(path): 46 | if isinstance(path, str_cls): 47 | try: 48 | path = path.encode(fs_encoding, 'strict') 49 | except UnicodeEncodeError: 50 | if not platform.is_linux(): 51 | raise 52 | path = path.encode(fs_fallback_encoding, 'strict') 53 | return path 54 | 55 | 56 | def decode(path): 57 | if isinstance(path, bytes_cls): 58 | try: 59 | path = path.decode(fs_encoding, 'strict') 60 | except UnicodeDecodeError: 61 | if not platform.is_linux(): 62 | raise 63 | path = path.decode(fs_fallback_encoding, 'strict') 64 | return path 65 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/utils/win32stat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2014 Thomas Amland 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """ 18 | :module: watchdog.utils.win32stat 19 | :synopsis: Implementation of stat with st_ino and st_dev support. 20 | 21 | Functions 22 | --------- 23 | 24 | .. autofunction:: stat 25 | 26 | """ 27 | 28 | import ctypes 29 | import ctypes.wintypes 30 | import stat as stdstat 31 | from collections import namedtuple 32 | 33 | 34 | INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value 35 | OPEN_EXISTING = 3 36 | FILE_READ_ATTRIBUTES = 0x80 37 | FILE_ATTRIBUTE_NORMAL = 0x80 38 | FILE_ATTRIBUTE_READONLY = 0x1 39 | FILE_ATTRIBUTE_DIRECTORY = 0x10 40 | FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 41 | FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 42 | 43 | 44 | class FILETIME(ctypes.Structure): 45 | _fields_ = [("dwLowDateTime", ctypes.wintypes.DWORD), 46 | ("dwHighDateTime", ctypes.wintypes.DWORD)] 47 | 48 | 49 | class BY_HANDLE_FILE_INFORMATION(ctypes.Structure): 50 | _fields_ = [('dwFileAttributes', ctypes.wintypes.DWORD), 51 | ('ftCreationTime', FILETIME), 52 | ('ftLastAccessTime', FILETIME), 53 | ('ftLastWriteTime', FILETIME), 54 | ('dwVolumeSerialNumber', ctypes.wintypes.DWORD), 55 | ('nFileSizeHigh', ctypes.wintypes.DWORD), 56 | ('nFileSizeLow', ctypes.wintypes.DWORD), 57 | ('nNumberOfLinks', ctypes.wintypes.DWORD), 58 | ('nFileIndexHigh', ctypes.wintypes.DWORD), 59 | ('nFileIndexLow', ctypes.wintypes.DWORD)] 60 | 61 | 62 | CreateFile = ctypes.windll.kernel32.CreateFileW 63 | CreateFile.restype = ctypes.wintypes.HANDLE 64 | CreateFile.argtypes = ( 65 | ctypes.c_wchar_p, 66 | ctypes.wintypes.DWORD, 67 | ctypes.wintypes.DWORD, 68 | ctypes.c_void_p, 69 | ctypes.wintypes.DWORD, 70 | ctypes.wintypes.DWORD, 71 | ctypes.wintypes.HANDLE, 72 | ) 73 | 74 | GetFileInformationByHandle = ctypes.windll.kernel32.GetFileInformationByHandle 75 | GetFileInformationByHandle.restype = ctypes.wintypes.BOOL 76 | GetFileInformationByHandle.argtypes = ( 77 | ctypes.wintypes.HANDLE, 78 | ctypes.wintypes.POINTER(BY_HANDLE_FILE_INFORMATION), 79 | ) 80 | 81 | CloseHandle = ctypes.windll.kernel32.CloseHandle 82 | CloseHandle.restype = ctypes.wintypes.BOOL 83 | CloseHandle.argtypes = (ctypes.wintypes.HANDLE,) 84 | 85 | 86 | StatResult = namedtuple('StatResult', 'st_dev st_ino st_mode st_mtime') 87 | 88 | def _to_mode(attr): 89 | m = 0 90 | if (attr & FILE_ATTRIBUTE_DIRECTORY): 91 | m |= stdstat.S_IFDIR | 0o111 92 | else: 93 | m |= stdstat.S_IFREG 94 | if (attr & FILE_ATTRIBUTE_READONLY): 95 | m |= 0o444 96 | else: 97 | m |= 0o666 98 | return m 99 | 100 | def _to_unix_time(ft): 101 | t = (ft.dwHighDateTime) << 32 | ft.dwLowDateTime 102 | return (t / 10000000) - 11644473600 103 | 104 | def stat(path): 105 | hfile = CreateFile(path, 106 | FILE_READ_ATTRIBUTES, 107 | 0, 108 | None, 109 | OPEN_EXISTING, 110 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 111 | None) 112 | if hfile == INVALID_HANDLE_VALUE: 113 | raise ctypes.WinError() 114 | info = BY_HANDLE_FILE_INFORMATION() 115 | r = GetFileInformationByHandle(hfile, info) 116 | CloseHandle(hfile) 117 | if not r: 118 | raise ctypes.WinError() 119 | return StatResult(st_dev=info.dwVolumeSerialNumber, 120 | st_ino=(info.nFileIndexHigh << 32) + info.nFileIndexLow, 121 | st_mode=_to_mode(info.dwFileAttributes), 122 | st_mtime=_to_unix_time(info.ftLastWriteTime) 123 | ) 124 | -------------------------------------------------------------------------------- /Packages/SourcePawn/watchdog/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2011 Yesudeep Mangalapilly 5 | # Copyright 2012 Google, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | # When updating this version number, please update the 21 | # ``docs/source/global.rst.inc`` file as well. 22 | VERSION_MAJOR = 0 23 | VERSION_MINOR = 8 24 | VERSION_BUILD = 0 25 | VERSION_INFO = (VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD) 26 | VERSION_STRING = "%d.%d.%d" % VERSION_INFO 27 | 28 | __version__ = VERSION_INFO 29 | -------------------------------------------------------------------------------- /Packages/User/Preferences.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "color_scheme": "Packages/User/SaucePawn.sublime-color-scheme", 3 | "font_face": "", 4 | "font_size": 9, 5 | "theme": "Adaptive.sublime-theme" 6 | } 7 | -------------------------------------------------------------------------------- /Packages/User/SaucePawn.sublime-color-scheme: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JS SourcePawn Theme", 3 | "globals": 4 | { 5 | "background": "#2c3e50", 6 | "foreground": "#f2e5d8", 7 | "caret": "#F8F8F0", 8 | "brackets_options": "foreground bold", 9 | "brackets_foreground": "#9deafa", 10 | "invisibles": "#49483E", 11 | "line_highlight": "#49483E", 12 | "selection": "#49483E", 13 | // "gutter": "#000000", 14 | // "gutter_foreground": "#ffffff", 15 | }, 16 | "rules": 17 | [ 18 | { 19 | "scope": "brackethighlighter.default", 20 | "background": "#d1d1d1", 21 | "foreground": "#f4f5f7" 22 | }, 23 | { 24 | "scope": "comment", 25 | "foreground": "#5b727f" 26 | }, 27 | // Constant 28 | { 29 | "scope": "constant", 30 | "foreground": "#74b8f9", 31 | }, 32 | { 33 | "scope": "constant.character, constant.other", 34 | "foreground": "#97cefc", 35 | }, 36 | { 37 | "scope": "constant.character.escape", 38 | "foreground": "#76a9d3", 39 | }, 40 | { 41 | "scope": "constant.language", 42 | "foreground": "#7fc0fa", 43 | "font_style": "italic bold", 44 | }, 45 | { 46 | "scope": "constant.numeric", 47 | "foreground": "#74b8f9", 48 | "font_style": "italic", 49 | }, 50 | // Entity 51 | { 52 | "scope": "entity.name.class", 53 | "foreground": "#31e0f7", 54 | "font_style": "bold italic underline" 55 | }, 56 | { 57 | "scope": "entity.name.constant", 58 | "foreground": "#dd96e0", 59 | "font_style": "bold italic" 60 | }, 61 | { 62 | "scope": "entity.name.enum", 63 | "foreground": "#31e0f7", 64 | "font_style": "bold italic", 65 | }, 66 | { 67 | "scope": "entity.name.function", 68 | "foreground": "#a7abfc", // c2c5f9 69 | "font_style": "bold italic" 70 | }, 71 | { 72 | "scope": "entity.name.struct", 73 | "foreground": "#31e0f7", 74 | "font_style": "bold italic underline", 75 | }, 76 | { 77 | "scope": "entity.name.tag", 78 | "foreground": "#ff785f" 79 | }, 80 | { 81 | "scope": "entity.name.trait", 82 | "foreground": "#A7F0A9", 83 | "font_style": "bold italic" 84 | }, 85 | { 86 | "scope": "entity.name.type", 87 | "foreground": "#31e0f7", 88 | "font_style": "bold italic", 89 | }, 90 | { 91 | "scope": "entity.other.attribute-name", 92 | "foreground": "#89e99c", 93 | }, 94 | { 95 | "scope" : "entity.other.inherited-class", 96 | "foreground": "#31e0f7", 97 | "font_style": "bold italic" 98 | }, 99 | // Invalid 100 | { 101 | "scope": "invalid", 102 | "foreground": "#F8F8F0", 103 | "background": "#F92672" 104 | }, 105 | { 106 | "scope": "invalid.deprecated", 107 | "background": "#AE81FF", 108 | "foreground": "#F8F8F0", 109 | }, 110 | { 111 | "scope": "invalid.illegal", 112 | "foreground": "#F8F8F0", 113 | "background": "#F92672", 114 | }, 115 | // KeyWord 116 | { 117 | "scope": "keyword", 118 | "foreground": "#ff624a", 119 | }, 120 | { 121 | "scope": "keyword.control", 122 | "foreground": "#ef7c66", 123 | // "font_style": "bold", 124 | }, 125 | { 126 | "scope": "keyword.control.flow", 127 | "foreground": "#ef7c66", 128 | "font_style": "italic", 129 | }, 130 | { 131 | "scope": "keyword.control.conditional", 132 | "foreground": "#ef7c66", 133 | "font_style": "" 134 | }, 135 | { 136 | "scope": "keyword.control.import", 137 | "foreground": "#ff624a", 138 | "font_style": "italic", 139 | }, 140 | { 141 | "scope": "keyword.declaration", 142 | "foreground": "#54afff", 143 | "font_style": "italic" 144 | }, 145 | { 146 | "scope": "keyword.operator", 147 | "foreground": "#ff624a", 148 | }, 149 | { 150 | "scope": "keyword.operator.bitwise", 151 | "foreground": "#e80202", 152 | }, 153 | { 154 | "scope": "keyword.operator.logical", 155 | "foreground": "#e80202", 156 | }, 157 | { 158 | "scope": "keyword.operator.word", 159 | "foreground":"#ef7c66" 160 | }, 161 | { 162 | "scope": "keyword.other", 163 | "foreground": "#54afff", 164 | "font_style": "bold", 165 | }, 166 | { 167 | "scope": "keyword.other.documentation", 168 | "foreground": "#de8071", 169 | "font_style": "" 170 | }, 171 | { 172 | "scope": "keyword.other.documentation.note", 173 | "foreground": "#de2323", 174 | // "font_style": "bold", 175 | }, 176 | // Meta 177 | { 178 | "scope": "meta", 179 | "foreground": "#ffffff", 180 | }, 181 | { 182 | "scope": "meta.preprocessor", 183 | "foreground": "#de8071", 184 | }, 185 | // Punctuation 186 | { 187 | "scope": "punctuation.accessor", 188 | "foreground": "#e80202", 189 | }, 190 | { 191 | "scope": "punctuation.definition", 192 | "foreground": "#b5837b", 193 | }, 194 | { 195 | "scope": "punctuation.definition.comment", 196 | "foreground": "#5b727f", 197 | }, 198 | { 199 | "scope": "punctuation.definition.generic", 200 | "foreground": "#ff624a", 201 | }, 202 | { 203 | "scope": "punctuation.definition.keyword", 204 | "foreground": "#a66c63", 205 | }, 206 | { 207 | "scope": "punctuation.definition.string", 208 | "foreground": "#f57a7a", 209 | }, 210 | { 211 | "scope": "punctuation.section.block", 212 | "foreground": "#ccdfff", 213 | "font_style": "bold", 214 | }, 215 | { 216 | "scope": "punctuation.section", 217 | "foreground": "#96b1d3", 218 | "font_style": "bold", 219 | }, 220 | { 221 | "scope": "punctuation.section.braces", 222 | "foreground": "#ccdfff", 223 | // "font_style": "bold", 224 | }, 225 | { 226 | "scope": "punctuation.section.brackets", 227 | "foreground": "#6f8fb7", 228 | }, 229 | { 230 | "scope": "punctuation.section.parens", 231 | "foreground": "#96b1d3", 232 | "font_style": "bold", 233 | }, 234 | { 235 | "scope": "punctuation.separator", 236 | "foreground": "#9fcbf2", 237 | }, 238 | { 239 | "scope": "punctuation.terminator", 240 | "foreground": "#21bfff", 241 | }, 242 | { 243 | "scope": "source", 244 | "foreground": "#ffffff" 245 | }, 246 | // Storage 247 | { 248 | "scope": "storage", 249 | "foreground": "#54afff", 250 | }, 251 | { 252 | "scope": "storage.modifier", 253 | "foreground": "#54afff", 254 | "font_style": "bold" 255 | 256 | }, 257 | { 258 | "scope": "storage.type", 259 | "foreground": "#66D9EF", 260 | // "font_style": "bold", 261 | }, 262 | { 263 | "scope": "string", 264 | "foreground": "#ffaaaa", 265 | "font_style":"italic" 266 | }, 267 | // Support 268 | { 269 | "scope": "support", 270 | "foreground": "#bbdaf2" 271 | }, 272 | { 273 | "scope": "support.constant", 274 | "foreground": "#dd96e0", 275 | "font_style": "bold italic" 276 | }, 277 | { 278 | "scope": "support.class", 279 | "foreground": "#31e0f7", 280 | "font_style": "bold italic" 281 | }, 282 | { 283 | "scope": "support.function", 284 | "foreground": "#a7abfc", 285 | "font_style": "bold" 286 | }, 287 | { 288 | "scope": "support.other.variable", 289 | "foreground": "#ffffff", 290 | "font_style": "bold" 291 | }, 292 | { 293 | "scope": "support.type", 294 | "foreground": "#66D9EF", 295 | "font_style": "italic" 296 | }, 297 | // Variable 298 | { 299 | "scope": "variable", 300 | "foreground": "#ffffff", 301 | }, 302 | { 303 | "scope": "variable.function", 304 | "foreground": "#8ed1b9", 305 | // "font_style": "bold" 306 | // "font_style": "italic" 307 | }, 308 | { 309 | "scope": "variable.language", 310 | "foreground": "#1fc6ab", 311 | "font_style":"italic" 312 | }, 313 | { 314 | "scope": "variable.other", 315 | "foreground": "#bbdaf2", 316 | // "font_style":"italic" 317 | }, 318 | { 319 | "scope": "variable.other.constant", 320 | "foreground": "#dd96e0", 321 | "font_style":"italic" 322 | }, 323 | { 324 | "scope": "variable.other.member", 325 | "foreground": "#ffaf4f", 326 | // "font_style":"italic bold" 327 | }, 328 | { 329 | "scope": "variable.other.readwrite", 330 | "foreground": "#ffffff", 331 | // "font_style":"italic" 332 | }, 333 | { 334 | "scope": "variable.parameter", 335 | "foreground": "#ffd687", 336 | // "font_style": "italic" 337 | }, 338 | ] 339 | } -------------------------------------------------------------------------------- /Packages/User/SourcePawn Completions.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "bootstrapped": true, 3 | // path to sourcemod "scripting/include" folder 4 | // Windows example: // Support for multiple directories. Searches top to bottom until it finds include 5 | // "include_directory": [ 6 | // "D:\\sourcemod\\scripting\\include", 7 | // "C:\\another\\sourcemod\\include", // optional 8 | /// "etc . . ." // optional 9 | // ], 10 | // OSX example: 11 | // "include_directory": [ 12 | // "/Users/ppalex/sourcemod/scripting/include", 13 | // "/Users/ppalex/some/other/sourcemod/scripting/include", // optional 14 | // "etc . . ." // optional 15 | // ], 16 | 17 | // delay (in seconds) before regenerating auto-completion snippets 18 | "live_refresh_delay": 1.0 19 | } 20 | -------------------------------------------------------------------------------- /Packages/User/bh_core.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "content_highlight_bar": true, 3 | "align_content_highlight_bar": true, 4 | "search_threshold": 10000, 5 | // Define region highlight styles 6 | "bracket_styles": { 7 | // "default" and "unmatched" styles are special 8 | // styles. If they are not defined here, 9 | // they will be generated internally with 10 | // internal defaults. 11 | 12 | // "default" style defines attributes that 13 | // will be used for any style that does not 14 | // explicitly define that attribute. So if 15 | // a style does not define a color, it will 16 | // use the color from the "default" style. 17 | "default": { 18 | "icon": "dot", 19 | // BH1's original default color for reference 20 | // "color": "entity.name.class", 21 | "color": "brackethighlighter.default", 22 | "style": "outline" 23 | }, 24 | 25 | // This particular style is used to highlight 26 | // unmatched bracekt pairs. It is a special 27 | // style. 28 | "unmatched": { 29 | "icon": "question", 30 | // "color": "brackethighlighter.unmatched", 31 | "style": "outline" 32 | }, 33 | // User defined region styles 34 | "curly": { 35 | "icon": "curly_bracket", 36 | // "color": "brackethighlighter.curly", 37 | "style": "outline" 38 | }, 39 | "round": { 40 | "icon": "round_bracket", 41 | // "color": "brackethighlighter.round", 42 | "style": "outline" 43 | }, 44 | "square": { 45 | "icon": "square_bracket", 46 | // "color": "brackethighlighter.square", 47 | "style": "outline" 48 | }, 49 | "angle": { 50 | "icon": "angle_bracket", 51 | // "color": "brackethighlighter.angle", 52 | "style": "outline" 53 | }, 54 | "tag": { 55 | "icon": "tag", 56 | // "color": "brackethighlighter.tag", 57 | "style": "outline" 58 | }, 59 | "single_quote": { 60 | "icon": "single_quote", 61 | // "color": "brackethighlighter.quote", 62 | "style": "outline" 63 | }, 64 | "double_quote": { 65 | "icon": "double_quote", 66 | // "color": "brackethighlighter.quote", 67 | "style": "outline" 68 | }, 69 | "regex": { 70 | "icon": "regex", 71 | // "color": "brackethighlighter.quote", 72 | "style": "outline" 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sourcepawn_sublime_stuff 2 | Theme, syntax highlighter, bracket highlighter, whatever 3 | 4 | Requires Sublime Text 4 (Dev) 5 | 6 | This stuff goes in %APPDATA%\Sublime Folder Name Here/ 7 | 8 | See https://github.com/JoinedSenses/sourcepawn_sublime_stuff/tree/master/Packages/SourcePawn for configuring 9 | 10 | 11 | --------------------------------------------------------------------------------