├── .editorconfig ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── ReleaseNotes.txt ├── appveyor.yml ├── bin ├── bin │ ├── ctags.exe │ ├── global.exe │ ├── gtags.conf │ ├── gtags.exe │ ├── pygments-parser.dll │ └── universal-ctags.dll └── share │ └── gtags │ └── script │ └── pygments_parser.py └── src ├── AboutWin.cpp ├── AboutWin.h ├── ActivityWin.cpp ├── ActivityWin.h ├── AutoCompleteWin.cpp ├── AutoCompleteWin.h ├── AutoLock.h ├── Cmd.cpp ├── Cmd.h ├── CmdDefines.h ├── CmdEngine.cpp ├── CmdEngine.h ├── Common.cpp ├── Common.h ├── Config.cpp ├── Config.h ├── DbManager.cpp ├── DbManager.h ├── DocLocation.cpp ├── DocLocation.h ├── GTags.cpp ├── GTags.h ├── INpp.cpp ├── INpp.h ├── LineParser.cpp ├── LineParser.h ├── NppAPI ├── Docking.h ├── Notepad_plus_msgs.h ├── PluginInterface.h ├── Sci_Position.h ├── Scintilla.h ├── dockingResource.h └── menuCmdID.h ├── PluginInterface.cpp ├── ReadPipe.cpp ├── ReadPipe.h ├── ResultWin.cpp ├── ResultWin.h ├── SearchWin.cpp ├── SearchWin.h ├── SettingsWin.cpp ├── SettingsWin.h ├── StrUniquenessChecker.h ├── nppgtags.ico ├── nppgtags.rc └── resource.h /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig configuration file 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = crlf 7 | tab_width = 4 8 | indent_style = space 9 | indent_size = tab 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *TAGS 2 | GPATH 3 | NppGTags.cfg 4 | *.suo 5 | *.sdf 6 | *.bat 7 | *.sh 8 | *.sln 9 | /Debug 10 | /Release 11 | /out 12 | /build 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.15) 2 | cmake_policy (SET CMP0091 NEW) 3 | 4 | set (CMAKE_SYSTEM_NAME Windows) 5 | 6 | if (UNIX OR MINGW) 7 | set (CMAKE_SYSROOT "/usr") 8 | 9 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 10 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 11 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 12 | 13 | if (WIN64) 14 | set (toolchain_prefix x86_64-w64-mingw32) 15 | else () 16 | set (toolchain_prefix i686-w64-mingw32) 17 | endif () 18 | 19 | set (CMAKE_C_COMPILER ${CMAKE_SYSROOT}/bin/${toolchain_prefix}-gcc) 20 | set (CMAKE_CXX_COMPILER ${CMAKE_SYSROOT}/bin/${toolchain_prefix}-g++) 21 | set (CMAKE_RC_COMPILER ${CMAKE_SYSROOT}/bin/${toolchain_prefix}-windres) 22 | 23 | set (win32_inc_dir ${CMAKE_SYSROOT}/${toolchain_prefix}/include) 24 | set (win32_lib_dir ${CMAKE_SYSROOT}/${toolchain_prefix}/lib) 25 | endif () 26 | 27 | project (NppGTags) 28 | 29 | set(CMAKE_CXX_STANDARD 14) 30 | 31 | if (UNIX OR MINGW) 32 | set (defs 33 | -DUNICODE -D_UNICODE -DMINGW_HAS_SECURE_API=1 -D_WIN32 -DWIN32 34 | -D_WIN32_WINNT=0x0600 -DWIN32_LEAN_AND_MEAN -DNOCOMM -DNDEBUG 35 | ) 36 | 37 | if (WIN64) 38 | set (defs ${defs} -D_WIN64) 39 | endif () 40 | 41 | if (DEVEL) 42 | set (defs ${defs} -DDEVEL) 43 | endif () 44 | 45 | set (CMAKE_CXX_FLAGS 46 | "-O3 -static-libgcc -static-libstdc++ -Wall -Wno-unknown-pragmas" 47 | ) 48 | 49 | set (CMAKE_MODULE_LINKER_FLAGS "-s") 50 | 51 | set (CMAKE_SHARED_MODULE_PREFIX "") 52 | else () 53 | set (CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 54 | 55 | if (CMAKE_CL_64 OR CMAKE_GENERATOR MATCHES Win64) 56 | set (defs 57 | -DUNICODE -D_UNICODE -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -D_WIN32 -DWIN32 58 | -D_WIN32_WINNT=0x0600 -DWIN32_LEAN_AND_MEAN -DNOCOMM -D_WIN64 59 | ) 60 | else () 61 | set (defs 62 | -DUNICODE -D_UNICODE -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -D_WIN32 -DWIN32 63 | -D_WIN32_WINNT=0x0600 -DWIN32_LEAN_AND_MEAN -DNOCOMM 64 | ) 65 | endif () 66 | 67 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /LD /MP /W4") 68 | endif () 69 | 70 | set (project_rc_files 71 | src/nppgtags.rc 72 | ) 73 | 74 | set (project_sources 75 | src/Common.cpp 76 | src/INpp.cpp 77 | src/PluginInterface.cpp 78 | src/ReadPipe.cpp 79 | src/GTags.cpp 80 | src/LineParser.cpp 81 | src/Cmd.cpp 82 | src/CmdEngine.cpp 83 | src/DbManager.cpp 84 | src/Config.cpp 85 | src/DocLocation.cpp 86 | src/ActivityWin.cpp 87 | src/SearchWin.cpp 88 | src/SettingsWin.cpp 89 | src/AboutWin.cpp 90 | src/AutoCompleteWin.cpp 91 | src/ResultWin.cpp 92 | ) 93 | 94 | add_definitions (${defs}) 95 | 96 | add_library (NppGTags MODULE ${project_rc_files} ${project_sources}) 97 | 98 | if (UNIX OR MINGW) 99 | include_directories (${win32_inc_dir}) 100 | 101 | find_library (comctl32 102 | NAMES libcomctl32.a 103 | PATHS ${win32_lib_dir} 104 | ) 105 | 106 | target_link_libraries (NppGTags ${comctl32}) 107 | 108 | set (INSTALL_PATH 109 | "$ENV{HOME}/.wine/drive_c/Program Files/Notepad++/plugins/NppGTags" 110 | ) 111 | 112 | message ("Install destination: ${INSTALL_PATH}") 113 | 114 | install (FILES ${CMAKE_BINARY_DIR}/NppGTags.dll 115 | DESTINATION "${INSTALL_PATH}" 116 | ) 117 | 118 | install (DIRECTORY bin/bin 119 | DESTINATION "${INSTALL_PATH}" 120 | ) 121 | 122 | install (DIRECTORY bin/share 123 | DESTINATION "${INSTALL_PATH}" 124 | ) 125 | else () 126 | target_link_libraries (NppGTags comctl32) 127 | endif () 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | To support NppGTags consider donating. Thank You. 2 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/pnedev) 3 | 4 | 5 | **--- NppGTags ---** 6 | ====================== 7 | **GTags plugin for Notepad++** 8 | 9 | This is a front-end to GNU Global source code tagging system (GTags) for Notepad++. It provides various functions to ease project code navigation - search for file, definition, reference, literal, regular expression, perform auto-completion. 10 | 11 | The GNU Global official website is https://www.gnu.org/software/global. 12 | 13 | You'll need GTags binaries for Windows (Win32 API) to use this plugin. Those are supplied with the plugin binary for convenience. 14 | You can also find Windows ported GTags binaries at http://adoxa.altervista.org/global. 15 | 16 | The Universal Ctags parser project website is https://ctags.io. 17 | 18 | 19 | **Build Status** 20 | ====================== 21 | 22 | AppVeyor [![Build status](https://ci.appveyor.com/api/projects/status/b4aam50a4q2vacd7?svg=true)](https://ci.appveyor.com/project/pnedev/nppgtags) 23 | 24 | 25 | **Installation** 26 | ====================== 27 | 28 | For Notepad++ versions 7.6.3 and above you can use the built-in PluginAdmin dialog (accessible through the *Plugins* menu). 29 | 30 | You can manually install the plugin by copying `NppGTags.dll`, `bin` folder (containing GTags and Universal Ctags binaries) and `share` folder (containing `pygments parser.py` script) to your Notepad++ plugins directory in a separate sub-folder named `NppGTags`. 31 | For Notepad++ versions below 7.6, the above files should be copied directly in Notepad++ plugins directory. 32 | Restart Notepad++ and you are all set. 33 | 34 | 35 | **Settings** 36 | ====================== 37 | 38 | Use plugin **Settings** to tune its operation. 39 | There are two types of settings - 'generic' plugin settings and database related settings. 40 | 41 | Among the 'generic' settings are: 42 | 43 | - Keep Search box open - if enabled the search box where you can enter searched tags will be held open after triggering the search. 44 | - Trigger autocomplete after char - if enabled the autocomplete will be triggered automatically after you type a word with lenght equal or bigger than the configured characters count. 45 | - The default database - if enabled it will be used to perform searches from active files (documents) in Notepad++ that don't have their own database (unparsed files). This is kind-of library database for unparsed files. 46 | 47 | The database related settings come in two distinct copies that are identical. 48 | One is regarding the settings default values for each newly generated database. You can access those at any time - just open the **Settings** window. 49 | The second one is the database settings for the currently used database (determined by the currently active document - somewhere in its path the database files reside). You can access those when you open **Settings** window while you are editing a project file. 50 | 51 | Among the database related settings are: 52 | 53 | - The code parser to be used while creating the database. 54 | The default is the built-in *GTags* parser but it supports only C, C++, Java, PHP and several other languages at the time this doc was written. 55 | *Ctags* (this is actually the Universal Ctags parser) supports considerably more languages and is continuously evolving but does not allow reference search. 56 | *Pygments* also supports lots of languages + reference search but requires external Python library (*Pygments*) that is not supplied with the plugin (as you need to have Python installed and *Pygments* library added for it via *pip* for example). 57 | 58 | From **Settings** you can also set the auto-update database behavior, the linked libraries databases (if any) and the ignored sub-paths. The linked libraries are completely manageable from the settings window (meaning they can be created and updated directly from there). The ignored sub-paths setting is used for results filtering - the configured database sub-paths will actually be searched as well but will be excluded from the search results. 59 | 60 | 61 | **Usage** 62 | ====================== 63 | 64 | You can find all supported commands in the NppGTags plugin menu. 65 | To make your life easier use Notepad++'s shortcut settings to assign whatever shortcuts you like to the plugin commands. There are no predefined shortcuts in the plugin to avoid possible conflicts with other Notepad++ plugins. 66 | 67 | To start using the plugin first you need to create GTags database for your project - **Create Database**. 68 | In the dialog simply select your project's top folder and GTags will index recursively all files supported by the chosen parser. It will create database files (*GTAGS*, *GRTAGS*, *GPATH* and *NppGTags.cfg*) in the selected folder. 69 | 70 | **Delete Database** invoked when a file from the project is the currently active document in Notepad++ will delete the above-mentioned files. 71 | 72 | If you run one of the plugin's **Find** commands (those include the **Search** commands as well) from any active document from the project it will search the database for: 73 | 74 | 1. what you have selected if there is selection; 75 | 2. the word that is under the caret if there is no selection; 76 | 3. what you have entered in the search box that will appear if there is no word under the caret. 77 | 78 | The search box allows choosing case sensitivity and regexp for the **Find** command where applicable. 79 | It also provides search completion list where possible which appears when you enter several characters in the box. 80 | If the **Find** command is started without the search box (case 1 and 2) the search is literal (no regexp) and the case sensitivity depends on the menu flag **Ignore Case**. 81 | 82 | **Find File** command will skip step 2, it will directly go to step 3 if there is no selection. 83 | It will automatically fill the search box (from step 3) with the name of the current file without the extension to make switching between source and header file easier. 84 | **Find File** will search for paths containing the given string (anywhere in the name) although its search completion will show only paths that start with the entered string. That means that even if there is no completion shown you can still perform the search and find files containing the entered string. 85 | All paths are relative to the project's directory. 86 | 87 | In GTags' terminology, *Symbol* is reference to identifier for which definition was not found. All local variables are symbols for example. 88 | If you search for *Definition* / *Reference* and GTags doesn't find anything the plugin will automatically invoke search for *Symbol*. This will be reported in the search results window header. 89 | 90 | Any **Search** will search for a string either "literally" (not using regular expressions) or using regular expressions if that is selected through the search box options. 91 | **Search in Source Files** will look only in files that are recognized as sources by the parser during database creation. 92 | **Search in Other Files** respectively will look in all other (non-binary) files. This is useful to dig into documentation (text files) or Makefiles for example. 93 | 94 | As a summary, **Find Definition / Reference** will search for identifiers (single whole words) whereas **Search...** will search for strings in general (parts of words, several consecutive words, etc.) either literally or using regular expressions. 95 | 96 | **AutoComplete** will show found *Definitions* + found *Symbols*. It will look for the string from the beginning of the word to the caret position. 97 | Autocomplete case sensitivity also depends on the menu flag **Ignore Case**. 98 | 99 | While auto complete results window is active you can narrow the results shown by continuing typing. 100 | *Backspace* will undo the narrowing one step at a time (as the newly typed characters are deleted). 101 | Double-clicking or pressing *Enter* or *Tab* will insert the selected auto complete result. 102 | 103 | **AutoComplete File Name** is useful if you will be including headers for example. 104 | 105 | **AutoComplete** and **Find Definition** commands will also search library databases if such are used. That is configured per database through the plugin's **Settings** window. 106 | 107 | All **Find** commands will show Notepad++ docking window with the results. The exception to this is if the result is just one - then you will be taken directly to its location. Otherwise the command results will be placed in a separate tab that will automatically become active (the docking window will receive focus). 108 | Clicking on another tab will show that command's results. You can also use the *ALT* + *Left* and *ALT* + *Right* arrow keys to switch between tabs. 109 | 110 | Double-clicking, hitting *Space* or *Enter* on search result line will take you to the source location. You can also do that by left-clicking on the highlighted searched word in the result line. Your currently edited document location will be saved - use **Go Back** command to visit it again. You can 'undo' the **Go Back** action by using **Go Forward** command. 111 | By using the mouse or the arrow keys you can move around result lines and you can trigger new searches directly from the results window 112 | (same rules about the searched string apply). 113 | 114 | Right clicking or hitting *ESC* will close the currently active search results tab. 115 | 116 | Left-clicking on the margin area ([+] / [-] signs) or pressing *'+'* / *'-'* keys will unfold / fold lines. To fold a line it is not necessary to click exactly the [-] sign in the margin - clicking on any sub-line's margin will do. Pressing *ALT* + *'+'* / *'-'* keys will unfold / fold all lines. 117 | You can accomplish that also by double-clicking or hitting *Space* or *Enter* on the search results header line - this will toggle all lines fold / unfold state. 118 | Clicking on header line margin or pressing *'+'* / *'-'* keys while head line is the active one will do the same. 119 | 120 | The results window is Scintilla window actually (same as Notepad++). This means that you can use *CTRL* + mouse scroll to zoom in / out or you can select text and copy it (*CTRL* + *'C'*). 121 | 122 | When the focus is on the results window pressing *CTRL* + *'F'* will open a search dialog. Fill-in what you are looking for and press *Enter*. The search dialog will remain open until you press *ESC*. While it is open you can continue searching by pressing *Enter* again. *Shift* + *Enter* searches backwards. If you close the search dialog you can continue searching for the same thing using *F3* and *Shift* + *F3* (forward or backward respectively). *F3* works while the search dialog is open as well. The search always wraps around when it reaches the results end - the Notepad++ window will blink to notify you in that case. 123 | 124 | When the focus is on the results window pressing *F5* will re-run the same search as the active results tab. This is kind-of active results tab refresh. 125 | 126 | **Toggle Windows Focus** command is added for convenience. It switches the focus between the edited document and the currently opened NppGTags windows (results window and search window). It's meant to be used with a shortcut so you can use the plugin through the keyboard entirely. 127 | 128 | Enjoy! 129 | -------------------------------------------------------------------------------- /ReleaseNotes.txt: -------------------------------------------------------------------------------- 1 | What's new in v5.2.0 2 | ======================= 3 | - Add multi-caret Autocomplete and possibility to triger autocomplete if configurable number of chars are typed 4 | - Made several Search box improvements related to its autocompletion and the box can now be configured to stay open 5 | - Toggle window now cycles also through Search box if it is open 6 | - Enable use of library DBs on other drives 7 | - Library DB paths (if configured and used) are now shown in results with their absolute paths 8 | - Update Global GTags binaries to 6.6.12 9 | - Several other fixes and improvements 10 | 11 | 12 | What's new in v5.1.2 13 | ======================= 14 | - Update Notepad++ API (>= Notepad++ v8.6.5 but it is compatible with older version as well) 15 | - Update Ctags to 6.1.0 and Global GTags binaries to 6.6.9 16 | - Several small fixes and improvements 17 | 18 | 19 | What's new in v5.1.1 20 | ======================= 21 | - Fix issue with swapped mouse buttons 22 | 23 | 24 | What's new in v5.1.0 25 | ======================= 26 | - Update Notepad++ and Scintilla API headers for latest Notepad++ versions 27 | 28 | 29 | What's new in v5.0.0 30 | ======================= 31 | - Auto-rerun active results tab search and auto-update results when database is updated 32 | - Directly visit single result 33 | - Auto-expand results if all of them are located in single file 34 | - Update Ctags to 5.9.20220508.0 and Global GTags binaries to 6.6.8 35 | - Updated for the new Scintilla 5 and Notepad++ versions above 8.4.1 36 | 37 | 38 | What's new in v4.5.0 39 | ======================= 40 | - Add summary of the hits count in every search header 41 | - Update Notepad++ API to match header changes after v8.2.2 42 | 43 | 44 | What's new in v4.4.3 45 | ======================= 46 | - No functional changes, just link statically to MSVC run-time library 47 | 48 | 49 | What's new in v4.4.2 50 | ======================= 51 | 52 | - Prompt for database creation if it is not found on user interaction. 53 | - Add "Ignore Case" option command to the menu - "Match Case" replaced by "Ignore Case". 54 | "Ignore Case" option always active (for the direct searches also not only via Search window). 55 | - Change platform toolset so XP is no longer supported. 56 | - Updated to Notepad++ 7.7 and above plugins API (and the new Scintilla). 57 | 58 | 59 | What's new in v4.4.1 60 | ======================= 61 | 62 | - Made find-in-results window horizontally scrollable. 63 | - Automatically add selected text in results window to the find-in-results text field. 64 | - Changed plugin's installation path according to the latest Notepad++'s requirements. 65 | - GTags binaries updated to v6.6.2. 66 | 67 | 68 | What's new in v4.4.0 69 | ======================= 70 | 71 | - Added search functionality in result window. 72 | - Added per-database config setting for excluding sub-paths from results. 73 | - Improve UI view and DPI awareness. 74 | - Fix bug for library DBs on different drive when the returned paths are absolute and were not correctly parsed 75 | (thanks to zavla - z.malinovskiy). 76 | - Fix bug in Activity window for the 64-bit version (thanks to YoungJoon Ahn). 77 | - Various optimizations. 78 | - GTags binaries updated to v6.5.6. 79 | 80 | 81 | What's new in v4.3.1 82 | ======================= 83 | 84 | - This is a bug fix release - Fixes possible problems on DB creation when the user selects his project's folder. 85 | 86 | 87 | What's new in v4.3.0 88 | ======================= 89 | 90 | - Updated for 64-bit Notepad++ support (please note that GTags binaries are still only 32-bit). 91 | - Triggering new search is now also possible directly from previous search results window tab - 92 | move the cursor in the results window using the arrow keys (use Shift to select) or using the mouse. 93 | - Fold / Unfold all result lines implemented - use result head line margin click (or Enter / Space in the head line) or 94 | Alt '+' / Alt '-' anywhere in the results window. 95 | - Moving between result tabs is now accomplished by Alt + Left / Alt + Right arrow keys. 96 | 97 | 98 | What's new in v4.2.1 99 | ======================= 100 | 101 | - This is a bug-fix release 102 | Fix generic database settings not read bug. 103 | Fix error case when DB path set does not end with '\'. 104 | 105 | 106 | What's new in v4.2.0 107 | ======================= 108 | 109 | - Default database search implemented 110 | The default database (if enabled) will be used for searches 111 | if no other database is detected for the active file. 112 | 113 | 114 | What's new in v4.1.0 115 | ======================= 116 | 117 | - Ctags and Pygments parsers are fully usable now 118 | - Save last SearchWin RegExp and MatchCase options state 119 | - Properly position dialogs on multi-monitor setups 120 | - Omit reoccurring results (those mainly appeared when library DBs were used) 121 | - Update to latest N++ plugin API 122 | - Fix problem with Environment settings 123 | - Several small fixes 124 | - Update GTAGS binaries to v6.5.3 125 | 126 | 127 | What's new in v4.0.0 128 | ======================= 129 | 130 | - Made configuration per database. 131 | This adds another file to the database ones (GTAGS, etc.) - NppGTags.cfg. 132 | The good thing is that each database can now be tuned separately from all the others - has its own defined 133 | libraries and parser. The auto-update database feature won't be corrupting the database anymore in case the 134 | database is created with one parser that is lately changed in the global settings. 135 | 136 | - Add 'Search in Other Files' command that will perform literal or regexp searches in text files, Makefiles or any 137 | other text files that are not recognized as sources by the parser during database creation 138 | 139 | - Auto-update database feature will now update all databases that have indexed the changed file 140 | - Add 'Update Library DBs' control in Settings window to easily update all project's libraries 141 | - Auto-complete now provides completion suggestions not for the whole word under the cursor but for the string from 142 | the beginning of the word to the cursor position 143 | 144 | - Code re-factored for improved stability and speed 145 | - Use STL containers instead of custom ones 146 | - Use single UI thread and dedicated command threads. 147 | This provides better UI experience, responsiveness and improved speed 148 | 149 | - Update Activity windows position when necessary for better user experience 150 | - Various tweaks, improvements and bug-fixes 151 | - About window now reports also the Ctags binary version 152 | 153 | - Update GTAGS binaries to v6.5.2 154 | - Use the new feature of v6.5.2 to ignore non parse-able files while creating native database 155 | (using the default parser). This does not abort database creation anymore 156 | 157 | 158 | What's new in v3.1.0 159 | ======================= 160 | 161 | - Improve search window auto-complete feature 162 | - Improve auto-complete speed 163 | - Fix issue with configurations when read from the config file 164 | 165 | 166 | What's new in v3.0.0 167 | ======================= 168 | 169 | - Add plugin config 170 | 171 | - The user can now select the code parser to be used - the default GTags, Ctags or Pygments 172 | (needs external Pygments Python package to be installed that is not provided with the plugin). 173 | Changing the parser will require database re-creation (to re-parse the code with the new parser). 174 | GTags parser supports C, C++, Java and several other languages. Ctags parser supports considerably more 175 | languages but doesn't support reference search. Pygments supports a lot of languages + reference search 176 | but requires external Python package. Database creation is also slower 177 | 178 | - The user can now create and set library databases to be used together with the project DB - 179 | library DBs are used only for definition searches and auto-completion 180 | 181 | - Major UI and code rework 182 | 183 | - The user can now set the search options (case sensitivity and regexp) through the search window together with 184 | the string to search. Not all search commands support regexp. If the search window is not used the search 185 | is case sensitive and literal (no regexp) by default 186 | 187 | - The search window provides auto-complete feature on the second char typed. Drop-down completion list will 188 | appear based on the text entered. On very large projects the auto-completion might take a while to finish 189 | 190 | - Results window automatically wraps long result lines so no horizontal scrolling is necessary 191 | 192 | - Results window is now fully controllable through the keyboard - Left and Right arrow keys switch between tabs, 193 | ESC key closes the active tab. Up and Down arrow keys move through results one at a time while Page-Up and 194 | Page-Down jump over whole screen of results. ENTER key now also opens result location or toggles fold 195 | (same as SPACE) 196 | 197 | - Results window style now more closely resembles Notepad++ theme. Use more neutral colors that look better on 198 | both light and dark themes 199 | 200 | - Add plugin command to toggle focus between results window and Notepad++ document. The user can assign 201 | shortcut key to this command through Notepad++ Shortcut Mapper to be able to switch focus easily 202 | 203 | - Add Go Forward plugin command to be able to 'undo' recent Go Back action 204 | 205 | - Unite Find Literal and Grep in a single Search command. The search is literal by default - the user can issue 206 | regexp search through the search window options 207 | 208 | - AutoComplete File now shows only valid filenames and paths, not partial ones 209 | 210 | - Auto Update database is now triggered on file rename and file delete also. This feature uses new Notepad++ 211 | notifications available since v6.7.5 212 | 213 | - Fix several bugs regarding database locking/unlocking 214 | 215 | - Error messages made more informative where possible 216 | 217 | - Numerous optimizations and fixes 218 | 219 | - Update GTags binaries to v6.5 220 | 221 | 222 | What's new in v2.3.0 223 | ======================= 224 | 225 | - Set fore, back and line colors from the selected Notepad++ theme 226 | - If the command reports warning or error but there are results anyway, show them 227 | - Fix bug when auto-updating DB for files with path length > 128 228 | 229 | 230 | What's new in v2.2.2 231 | ======================= 232 | 233 | - Fix bug in search match highlighting on single result line for Grep command 234 | 235 | 236 | What's new in v2.2.1 237 | ======================= 238 | 239 | - Fix bug in hotspot click for Find File command 240 | 241 | 242 | What's new in v2.2.0 243 | ======================= 244 | 245 | - Fix styling bug when switching from FindFile tab to other search tab and vice-versa 246 | - Fix race condition crash during styling 247 | - Make folding view more appealing 248 | - Make search word in the result click-able as a link to ease code navigation 249 | - Change cursor to reflect its position and the tab switch action 250 | - Highlight all search word occurrences in a single line 251 | 252 | 253 | What's new in v2.1.0 254 | ======================= 255 | 256 | - Show search type in results window tab name 257 | - Remember and restore folded state on tab switch 258 | - Clicking anywhere in expanded fold margin now collapses it (it is no longer necessary to click exactly [-] to collapse) 259 | - Header info is no longer fold-able 260 | - Tab name font is "Tahoma" and the font size is results font size - 1 261 | - Colorize search results line numbers for better viewing 262 | - Colorize and open regexp (GREP) search results correctly 263 | - Various fixes 264 | - Update GTags binaries to v6.3.4. This is a bug fix release 265 | 266 | 267 | What's new in v2.0.2 268 | ======================= 269 | 270 | - Remove the last empty line from the ScintillaUI window 271 | - ScintillaUI double-click action made smarter - now it detects double-click on the whole line 272 | - New DocLocation entry added only if the last one is not the same 273 | - Activity window show delay is handled better 274 | - New global.exe that does case sensitive path/file search 275 | 276 | 277 | What's new in v2.0.1 278 | ======================= 279 | 280 | - Use Scintilla to display results - colorized results and better navigation 281 | - Code refactoring and optimization 282 | - Minor fixes to GTags binaries v6.3.3 283 | 284 | 285 | What's new in v1.1.1 286 | ======================= 287 | 288 | - Replace all deprecated Win32 APIs with their recommended counterparts 289 | - Fix possible memory leaks connected to wrong Win32 API usage 290 | - Optimized code 291 | - GTags binaries updated to v6.3.3 292 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: Build {Build} 2 | image: Visual Studio 2022 3 | 4 | matrix: 5 | fast_finish: true 6 | 7 | environment: 8 | matrix: 9 | - PlatformToolset: v143 10 | 11 | platform: 12 | - x64 13 | - x86 14 | 15 | configuration: 16 | - Release 17 | - Debug 18 | 19 | install: 20 | - if "%platform%"=="x64" set archi=amd64 21 | - if "%platform%"=="x64" set platform_input=x64 22 | 23 | - if "%platform%"=="x86" set archi=x86 24 | - if "%platform%"=="x86" set platform_input=x86 25 | 26 | - if "%PlatformToolset%"=="v143" call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %archi% 27 | 28 | before_build: 29 | - ps: | 30 | Write-Output "Configuration: $env:CONFIGURATION" 31 | Write-Output "Platform: $env:PLATFORM_INPUT" 32 | $generator = switch ($env:PLATFORMTOOLSET) 33 | { 34 | "v143" {"Visual Studio 17 2022"} 35 | } 36 | # cmake build type, depended on the used generator, see https://cmake.org/cmake/help/v3.6/variable/CMAKE_BUILD_TYPE.html#variable:CMAKE_BUILD_TYPE 37 | # seems vs build always needs also the debug config, choose via the config option to the build command 38 | $build_type = "-DCMAKE_CONFIGURATION_TYPES=""Debug;Release"" " 39 | $build_config = "--config $env:CONFIGURATION" 40 | Write-Output "build_type: $build_type" 41 | Write-Output "build_config: $build_config" 42 | 43 | build_script: 44 | - ps: | 45 | cd c:\projects\nppgtags\ 46 | md _build -Force | Out-Null 47 | cd _build 48 | if ($env:PLATFORM_INPUT -eq "x64") 49 | { 50 | & cmake -G "$generator" -A x64 $build_type .. 51 | } 52 | else 53 | { 54 | & cmake -G "$generator" -A Win32 $build_type .. 55 | } 56 | if ($LastExitCode -ne 0) { 57 | throw "Exec: $ErrorMessage" 58 | } 59 | & cmake --build . --config $env:CONFIGURATION 60 | if ($LastExitCode -ne 0) { 61 | throw "Exec: $ErrorMessage" 62 | } 63 | 64 | after_build: 65 | - ps: | 66 | cd c:\projects\nppgtags\ 67 | 68 | $NppGTagsFileName = "NppGTags.$env:PLATFORM_INPUT.$env:CONFIGURATION.$env:PLATFORMTOOLSET.dll" 69 | Push-AppveyorArtifact "_build\$env:CONFIGURATION\NppGTags.dll" -FileName "$NppGTagsFileName" 70 | 71 | if ($($env:APPVEYOR_REPO_TAG) -eq "true" -and $env:CONFIGURATION -eq "Release") 72 | { 73 | $ZipFileName = "NppGTags_$($env:APPVEYOR_REPO_TAG_NAME)_$env:PLATFORM_INPUT.zip" 74 | md deploy -Force | Out-Null 75 | md deploy\NppGTags -Force | Out-Null 76 | Copy-Item _build\$env:CONFIGURATION\NppGTags.dll deploy\NppGTags\NppGTags.dll 77 | Copy-Item bin\* deploy\NppGTags\ -Recurse 78 | 7z a $ZipFileName .\deploy\NppGTags\* 79 | Remove-Item deploy\NppGTags\* -Recurse 80 | } 81 | 82 | artifacts: 83 | - path: NppGTags_*.zip 84 | name: releases 85 | -------------------------------------------------------------------------------- /bin/bin/ctags.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/bin/bin/ctags.exe -------------------------------------------------------------------------------- /bin/bin/global.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/bin/bin/global.exe -------------------------------------------------------------------------------- /bin/bin/gtags.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/bin/bin/gtags.exe -------------------------------------------------------------------------------- /bin/bin/pygments-parser.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/bin/bin/pygments-parser.dll -------------------------------------------------------------------------------- /bin/bin/universal-ctags.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/bin/bin/universal-ctags.dll -------------------------------------------------------------------------------- /bin/share/gtags/script/pygments_parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2014 4 | # Yoshitaro Makise 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from __future__ import print_function 20 | import io 21 | import os 22 | import subprocess 23 | import sys 24 | import re 25 | import string 26 | import optparse 27 | import pygments.lexers 28 | from pygments.token import Token 29 | 30 | EXUBERANT_CTAGS = "../../../bin/ctags.exe" 31 | 32 | # In most cases, lexers can be looked up with lowercase form of formal 33 | # language names. This dictionary defines exceptions. 34 | LANGUAGE_ALIASES = { 35 | 'fantom': 'fan', 36 | 'haxe': 'haXe', 37 | 'sourcepawn': 'sp', 38 | 'typescript': 'ts', 39 | 'xbase': 'XBase' 40 | } 41 | 42 | # All punctuation characters except some characters which are valid 43 | # identifier characters in some languages 44 | if sys.version_info < (3,): 45 | PUNCTUATION_CHARACTERS = string.punctuation.translate(None, '-_.') 46 | else: 47 | PUNCTUATION_CHARACTERS = string.punctuation.translate(str.maketrans('', '', '-_.')) 48 | 49 | CLOSEFDS = sys.platform != 'win32'; 50 | 51 | TERMINATOR = '###terminator###\n' 52 | 53 | class ParserOptions: 54 | def __init__(self): 55 | self.strip_punctuation = False 56 | 57 | class PygmentsParser: 58 | class ContentParser: 59 | def __init__(self, path, text, lexer, options): 60 | self.path = path 61 | self.text = text 62 | self.lexer = lexer 63 | self.options = options 64 | self.lines_index = None 65 | 66 | def parse(self): 67 | self.lines_index = self.build_lines_index(self.text) 68 | tokens = self.lexer.get_tokens_unprocessed(self.text) 69 | return self.parse_tokens(tokens) 70 | 71 | # builds index of beginning of line 72 | def build_lines_index(self, text): 73 | lines_index = [] 74 | cur = 0 75 | while True: 76 | i = text.find('\n', cur) 77 | if i == -1: 78 | break 79 | cur = i + 1 80 | lines_index.append(cur) 81 | lines_index.append(len(text)) # sentinel 82 | return lines_index 83 | 84 | def parse_tokens(self, tokens): 85 | result = {} 86 | cur_line = 0 87 | for index, tokentype, tag in tokens: 88 | if tokentype in Token.Name: 89 | # we can assume index are delivered in ascending order 90 | while self.lines_index[cur_line] <= index: 91 | cur_line += 1 92 | tag = re.sub(r'\s+', '', tag) # remove newline and spaces 93 | if self.options.strip_punctuation: 94 | tag = tag.strip(PUNCTUATION_CHARACTERS) 95 | if tag: 96 | result[(False, tag, cur_line + 1)] = '' 97 | return result 98 | 99 | def __init__(self, langmap, options): 100 | self.langmap = langmap 101 | self.options = options 102 | 103 | def parse(self, path): 104 | lexer = self.get_lexer_by_langmap(path) 105 | if lexer: 106 | text = self.read_file(path) 107 | if text: 108 | parser = self.ContentParser(path, text, lexer, self.options) 109 | return parser.parse() 110 | return {} 111 | 112 | def get_lexer_by_langmap(self, path): 113 | ext = os.path.splitext(path)[1] 114 | if sys.platform == 'win32': 115 | lang = self.langmap.get(ext.lower(), None) 116 | else: 117 | lang = self.langmap.get(ext, None) 118 | if lang: 119 | name = lang.lower() 120 | if name in LANGUAGE_ALIASES: 121 | name = LANGUAGE_ALIASES[name] 122 | lexer = pygments.lexers.get_lexer_by_name(name) 123 | return lexer 124 | return None 125 | 126 | def read_file(self, path): 127 | try: 128 | if sys.version_info < (3,): 129 | with open(path, 'r') as f: 130 | text = f.read() 131 | return text 132 | else: 133 | with open(path, 'r', encoding='latin1') as f: 134 | text = f.read() 135 | return text 136 | except Exception as e: 137 | print(e, file=sys.stderr) 138 | return None 139 | 140 | class CtagsParser: 141 | def __init__(self, ctags_command, options): 142 | self.process = subprocess.Popen([ctags_command, '-xu', '--filter', '--filter-terminator=' + TERMINATOR, '--format=1'], bufsize=-1, 143 | stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=CLOSEFDS, 144 | universal_newlines=True) 145 | if sys.version_info < (3,): 146 | self.child_stdout = self.process.stdout 147 | else: 148 | self.child_stdout = io.TextIOWrapper(self.process.stdout.buffer, encoding='latin1') 149 | sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='latin1') 150 | self.child_stdin = self.process.stdin 151 | self.options = options 152 | 153 | def parse(self, path): 154 | print(path, file=self.child_stdin) 155 | self.child_stdin.flush() 156 | result = {} 157 | while True: 158 | line = self.child_stdout.readline() 159 | if not line or line.startswith(TERMINATOR): 160 | break 161 | match = re.search(r'(\S+)\s+(\d+)\s+' + re.escape(path) + r'\s+(.*)$', line) 162 | if match: 163 | (tag, lnum, image) = match.groups() 164 | if self.options.strip_punctuation: 165 | tag = tag.strip(PUNCTUATION_CHARACTERS) 166 | if tag: 167 | result[(True, tag, int(lnum))] = image 168 | return result 169 | 170 | class MergingParser: 171 | def __init__(self, def_parser, ref_parser): 172 | self.def_parser = def_parser 173 | self.ref_parser = ref_parser 174 | pass 175 | 176 | def parse(self, path): 177 | def_result = self.def_parser.parse(path) 178 | ref_result = self.ref_parser.parse(path) 179 | result = def_result.copy() 180 | result.update(ref_result) 181 | for (isdef, tag, lnum) in def_result: 182 | ref_entry = (False, tag, lnum) 183 | if ref_entry in ref_result: 184 | del result[ref_entry] 185 | return result 186 | 187 | def parse_langmap(string): 188 | langmap = {} 189 | mappings = string.split(',') 190 | for mapping in mappings: 191 | lang, exts = mapping.split(':') 192 | if not lang[0].islower(): # skip lowercase, that is for builtin parser 193 | for ext in exts.split('.'): 194 | if ext: 195 | if sys.platform == 'win32': 196 | langmap['.' + ext.lower()] = lang 197 | else: 198 | langmap['.' + ext] = lang 199 | return langmap 200 | 201 | def handle_requests(langmap, options): 202 | global EXUBERANT_CTAGS 203 | if EXUBERANT_CTAGS != '' and EXUBERANT_CTAGS != 'no': 204 | ctags_bin = os.path.join(os.path.dirname(__file__), EXUBERANT_CTAGS) 205 | pygments_parser = PygmentsParser(langmap, options) 206 | try: 207 | ctags_parser = CtagsParser(ctags_bin, options) 208 | parser = MergingParser(ctags_parser, pygments_parser) 209 | except Exception as e: 210 | parser = pygments_parser 211 | else: 212 | parser = PygmentsParser(langmap, options) 213 | while True: 214 | path = sys.stdin.readline() 215 | if not path: 216 | break 217 | path = path.rstrip() 218 | tags = parser.parse(path) 219 | for (isdef, tag, lnum),image in tags.items(): 220 | if isdef: 221 | typ = 'D' 222 | else: 223 | typ = 'R' 224 | print(typ, tag, lnum, path, image) 225 | print(TERMINATOR, end='') 226 | sys.stdout.flush() 227 | 228 | def get_parser_options_from_env(parser_options): 229 | env = os.getenv('GTAGSPYGMENTSOPTS') 230 | if env: 231 | for s in env.split(','): 232 | s = s.strip() 233 | if s == 'strippunctuation': 234 | parser_options.strip_punctuation = True 235 | 236 | def main(): 237 | opt_parser = optparse.OptionParser() 238 | opt_parser.add_option('--langmap', dest='langmap') 239 | (options, args) = opt_parser.parse_args() 240 | if not options.langmap: 241 | opt_parser.error('--langmap option not given') 242 | langmap = parse_langmap(options.langmap) 243 | parser_options = ParserOptions() 244 | get_parser_options_from_env(parser_options) 245 | handle_requests(langmap, parser_options) 246 | 247 | if __name__ == '__main__': 248 | main() 249 | -------------------------------------------------------------------------------- /src/AboutWin.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief About window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma comment (lib, "comctl32") 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "Common.h" 34 | #include "INpp.h" 35 | #include "GTags.h" 36 | #include "AboutWin.h" 37 | 38 | 39 | namespace GTags 40 | { 41 | 42 | const TCHAR AboutWin::cClassName[] = _T("AboutWin"); 43 | const int AboutWin::cBackgroundColor = COLOR_INFOBK; 44 | const unsigned AboutWin::cFontSize = 10; 45 | 46 | 47 | std::unique_ptr AboutWin::AW {nullptr}; 48 | 49 | 50 | /** 51 | * \brief 52 | */ 53 | void AboutWin::Show(const TCHAR* info) 54 | { 55 | if (AW) 56 | { 57 | SetFocus(AW->_hWnd); 58 | return; 59 | } 60 | 61 | WNDCLASS wc = {0}; 62 | wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; 63 | wc.lpfnWndProc = wndProc; 64 | wc.hInstance = HMod; 65 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 66 | wc.hbrBackground = GetSysColorBrush(cBackgroundColor); 67 | wc.lpszClassName = cClassName; 68 | 69 | RegisterClass(&wc); 70 | 71 | INITCOMMONCONTROLSEX icex = {0}; 72 | icex.dwSize = sizeof(icex); 73 | icex.dwICC = ICC_STANDARD_CLASSES; 74 | 75 | InitCommonControlsEx(&icex); 76 | 77 | HWND hOwner = INpp::Get().GetHandle(); 78 | 79 | AW = std::make_unique(); 80 | 81 | if (AW->composeWindow(hOwner, info) == NULL) 82 | AW = nullptr; 83 | } 84 | 85 | 86 | /** 87 | * \brief 88 | */ 89 | AboutWin::~AboutWin() 90 | { 91 | if (_hFont) 92 | DeleteObject(_hFont); 93 | 94 | UnregisterClass(cClassName, HMod); 95 | } 96 | 97 | 98 | /** 99 | * \brief 100 | */ 101 | HWND AboutWin::composeWindow(HWND hOwner, const TCHAR* info) 102 | { 103 | DWORD styleEx = WS_EX_OVERLAPPEDWINDOW | WS_EX_TOOLWINDOW; 104 | DWORD style = WS_POPUP | WS_CAPTION | WS_SYSMENU; 105 | 106 | RECT win = Tools::GetWinRect(hOwner, styleEx, style, 300, 200); 107 | 108 | _hWnd = CreateWindowEx(styleEx, cClassName, _T("About ") PLUGIN_NAME, style, 109 | win.left, win.top, win.right - win.left, win.bottom - win.top, 110 | hOwner, NULL, HMod, NULL); 111 | if (_hWnd == NULL) 112 | return NULL; 113 | 114 | INpp::Get().RegisterWinForDarkMode(_hWnd); 115 | 116 | GetClientRect(_hWnd, &win); 117 | 118 | style = WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE | ES_READONLY | ES_NOOLEDRAGDROP; 119 | 120 | HWND hEdit = CreateWindowEx(0, RICHEDIT_CLASS, NULL, style, 121 | 0, 0, win.right - win.left, win.bottom - win.top, 122 | _hWnd, NULL, HMod, NULL); 123 | 124 | SendMessage(hEdit, EM_SETBKGNDCOLOR, 0, GetSysColor(cBackgroundColor)); 125 | 126 | HDC hdc = GetWindowDC(hEdit); 127 | _hFont = Tools::CreateFromSystemMessageFont(hdc, cFontSize); 128 | ReleaseDC(hEdit, hdc); 129 | 130 | if (_hFont) 131 | SendMessage(hEdit, WM_SETFONT, (WPARAM)_hFont, TRUE); 132 | 133 | DWORD events = ENM_KEYEVENTS | ENM_MOUSEEVENTS | ENM_REQUESTRESIZE | ENM_LINK; 134 | SendMessage(hEdit, EM_SETEVENTMASK, 0, events); 135 | SendMessage(hEdit, EM_AUTOURLDETECT, TRUE, 0); 136 | 137 | CText str(_T("\n")); 138 | str += VER_DESCRIPTION; 139 | str += _T("\n\nVersion: "); 140 | str += VER_VERSION_STR; 141 | str += _T("\nBuild date: "); 142 | str += _T(__DATE__); 143 | str += _T(','); 144 | str += _T(' '); 145 | str += _T(__TIME__); 146 | str += _T('\n'); 147 | str += VER_COPYRIGHT; 148 | str += _T(" "); 149 | str += _T("\nURL: "); 150 | str += VER_URL; 151 | str += _T("\n\nUser Guide: "); 152 | str += VER_USER_GUIDE; 153 | str += _T("\n\nLicensed under GNU GPLv2 as published by the Free Software Foundation.\n\n") 154 | _T("This plugin is frontend to GNU Global source code tagging system (GTags):\n") 155 | _T("https://www.gnu.org/software/global\n") 156 | _T("Windows ported GTags binaries can be found at:\n") 157 | _T("http://adoxa.altervista.org/global\n\n") 158 | _T("Thanks to:\n\tShigio YAMAGUCHI (the GNU Global developer) and all GTags contributors;\n") 159 | _T("\tJason Hood for porting GTags to Windows.\n") 160 | _T("Thanks also to all Universal Ctags parser developers.\n\n") 161 | _T("Current GTags version:\n\n"); 162 | str += info; 163 | 164 | Edit_SetText(hEdit, str.C_str()); 165 | 166 | ShowWindow(_hWnd, SW_SHOWNORMAL); 167 | UpdateWindow(_hWnd); 168 | 169 | return _hWnd; 170 | } 171 | 172 | 173 | /** 174 | * \brief 175 | */ 176 | LRESULT APIENTRY AboutWin::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 177 | { 178 | switch (uMsg) 179 | { 180 | case WM_CREATE: 181 | return 0; 182 | 183 | case WM_COMMAND: 184 | if (HIWORD(wParam) == EN_SETFOCUS) 185 | { 186 | DestroyCaret(); 187 | SetFocus(hWnd); 188 | return 0; 189 | } 190 | break; 191 | 192 | case WM_KEYDOWN: 193 | if (wParam == VK_ESCAPE) 194 | { 195 | SendMessage(hWnd, WM_CLOSE, 0, 0); 196 | return 0; 197 | } 198 | break; 199 | 200 | case WM_NOTIFY: 201 | switch (((LPNMHDR)lParam)->code) 202 | { 203 | case EN_MSGFILTER: 204 | { 205 | DestroyCaret(); 206 | MSGFILTER* pMsgFilter = (MSGFILTER*)lParam; 207 | if ((pMsgFilter->msg != WM_LBUTTONDOWN) && (pMsgFilter->msg != WM_LBUTTONUP)) 208 | return 1; 209 | } 210 | break; 211 | 212 | case EN_REQUESTRESIZE: 213 | { 214 | REQRESIZE* pReqResize = (REQRESIZE*)lParam; 215 | HWND hEdit = pReqResize->nmhdr.hwndFrom; 216 | int width = pReqResize->rc.right - pReqResize->rc.left + 30; 217 | int height = pReqResize->rc.bottom - pReqResize->rc.top; 218 | 219 | RECT win = Tools::GetWinRect(GetParent(hWnd), (DWORD)GetWindowLongPtr(hWnd, GWL_EXSTYLE), 220 | (DWORD)GetWindowLongPtr(hWnd, GWL_STYLE), width, height); 221 | MoveWindow(hWnd, win.left, win.top, win.right - win.left, win.bottom - win.top, TRUE); 222 | GetClientRect(hWnd, &win); 223 | MoveWindow(hEdit, 0, 0, win.right - win.left, win.bottom - win.top, TRUE); 224 | } 225 | return 1; 226 | 227 | case EN_LINK: 228 | { 229 | ENLINK* pEnLink = (ENLINK*)lParam; 230 | if (pEnLink->msg == WM_LBUTTONUP) 231 | { 232 | CText link(pEnLink->chrg.cpMax - pEnLink->chrg.cpMin); 233 | TEXTRANGE range; 234 | range.chrg = pEnLink->chrg; 235 | range.lpstrText = link.C_str(); 236 | SendMessage(pEnLink->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM) &range); 237 | ShellExecute(NULL, _T("open"), link.C_str(), NULL, NULL, SW_SHOWNORMAL); 238 | return 1; 239 | } 240 | } 241 | } 242 | break; 243 | 244 | case WM_DESTROY: 245 | DestroyCaret(); 246 | AW = nullptr; 247 | return 0; 248 | } 249 | 250 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 251 | } 252 | 253 | } // namespace GTags 254 | -------------------------------------------------------------------------------- /src/AboutWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief About window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace GTags 33 | { 34 | 35 | /** 36 | * \class AboutWin 37 | * \brief 38 | */ 39 | class AboutWin 40 | { 41 | public: 42 | static void Show(const TCHAR *info); 43 | 44 | AboutWin() : _hWnd(NULL), _hFont(NULL) {} 45 | ~AboutWin(); 46 | 47 | private: 48 | static const TCHAR cClassName[]; 49 | static const int cBackgroundColor; 50 | static const unsigned cFontSize; 51 | 52 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 53 | 54 | AboutWin(const AboutWin&); 55 | 56 | HWND composeWindow(HWND hOwner, const TCHAR* info); 57 | 58 | static std::unique_ptr AW; 59 | 60 | HWND _hWnd; 61 | HFONT _hFont; 62 | }; 63 | 64 | } // namespace GTags 65 | -------------------------------------------------------------------------------- /src/ActivityWin.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Process Activity window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2016 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma comment (lib, "comctl32") 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | #include "INpp.h" 33 | #include "GTags.h" 34 | #include "ActivityWin.h" 35 | 36 | 37 | namespace GTags 38 | { 39 | 40 | const TCHAR ActivityWin::cClassName[] = _T("ActivityWin"); 41 | const int ActivityWin::cBackgroundColor = COLOR_WINDOW; 42 | const unsigned ActivityWin::cFontSize = 8; 43 | const int ActivityWin::cWidth = 600; 44 | 45 | 46 | std::list ActivityWin::WindowList; 47 | HFONT ActivityWin::HFont = NULL; 48 | unsigned ActivityWin::TxtHeight = 0; 49 | 50 | 51 | /** 52 | * \brief 53 | */ 54 | void ActivityWin::Register() 55 | { 56 | WNDCLASS wc = {0}; 57 | wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; 58 | wc.lpfnWndProc = wndProc; 59 | wc.hInstance = HMod; 60 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 61 | wc.hbrBackground = GetSysColorBrush(cBackgroundColor); 62 | wc.lpszClassName = cClassName; 63 | 64 | RegisterClass(&wc); 65 | 66 | INITCOMMONCONTROLSEX icex = {0}; 67 | icex.dwSize = sizeof(icex); 68 | icex.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS; 69 | 70 | InitCommonControlsEx(&icex); 71 | } 72 | 73 | 74 | /** 75 | * \brief 76 | */ 77 | void ActivityWin::Unregister() 78 | { 79 | UnregisterClass(cClassName, HMod); 80 | } 81 | 82 | 83 | /** 84 | * \brief 85 | */ 86 | void ActivityWin::Show(const TCHAR* text, HANDLE hCancel) 87 | { 88 | if (!hCancel) 89 | return; 90 | 91 | ActivityWin* aw = new ActivityWin(hCancel); 92 | if (aw->composeWindow(text) == NULL) 93 | delete aw; 94 | } 95 | 96 | 97 | /** 98 | * \brief 99 | */ 100 | void ActivityWin::UpdatePositions() 101 | { 102 | int i = 1; 103 | for (auto iWin = WindowList.begin(); iWin != WindowList.end(); ++iWin, ++i) 104 | (*iWin)->onResize(i); 105 | } 106 | 107 | 108 | /** 109 | * \brief 110 | */ 111 | HWND ActivityWin::GetHwnd(HANDLE hCancel) 112 | { 113 | for (auto iWin = WindowList.begin(); iWin != WindowList.end(); ++iWin) 114 | { 115 | if ((*iWin)->_hCancel == hCancel) 116 | return (*iWin)->_hWnd; 117 | } 118 | 119 | return NULL; 120 | } 121 | 122 | 123 | /** 124 | * \brief 125 | */ 126 | ActivityWin::~ActivityWin() 127 | { 128 | for (auto iWin = WindowList.begin(); iWin != WindowList.end(); ++iWin) 129 | { 130 | if (*iWin == this) 131 | { 132 | WindowList.erase(iWin); 133 | break; 134 | } 135 | } 136 | 137 | if (WindowList.empty()) 138 | { 139 | if (HFont) 140 | DeleteObject(HFont); 141 | } 142 | else 143 | { 144 | int i = 1; 145 | for (auto iWin = WindowList.begin(); iWin != WindowList.end(); ++iWin, ++i) 146 | (*iWin)->onResize(i); 147 | } 148 | } 149 | 150 | 151 | /** 152 | * \brief 153 | */ 154 | void ActivityWin::adjustSizeAndPos(int width, int height, int winNum) 155 | { 156 | HWND hBias = INpp::Get().GetSciHandle(0); 157 | 158 | RECT maxWin; 159 | GetWindowRect(hBias, &maxWin); 160 | 161 | RECT win = {0}; 162 | win.right = width; 163 | win.bottom = height; 164 | 165 | AdjustWindowRect(&win, (DWORD)GetWindowLongPtr(_hWnd, GWL_STYLE), FALSE); 166 | 167 | width = win.right - win.left; 168 | height = win.bottom - win.top; 169 | win.left = maxWin.left; 170 | win.right = win.left + width; 171 | 172 | if (win.right > maxWin.right) 173 | win.right = maxWin.right; 174 | 175 | win.top = maxWin.bottom - (winNum * height); 176 | win.bottom = win.top + height; 177 | 178 | MoveWindow(_hWnd, win.left, win.top, win.right - win.left, win.bottom - win.top, TRUE); 179 | } 180 | 181 | 182 | /** 183 | * \brief 184 | */ 185 | HWND ActivityWin::composeWindow(const TCHAR* text) 186 | { 187 | _hWnd = CreateWindow(cClassName, NULL, WS_POPUP | WS_BORDER, 188 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 189 | INpp::Get().GetHandle(), NULL, HMod, this); 190 | if (_hWnd == NULL) 191 | return NULL; 192 | 193 | INpp::Get().RegisterWinForDarkMode(_hWnd); 194 | 195 | if (WindowList.empty()) 196 | { 197 | HWND hParent = INpp::Get().GetHandle(); 198 | HDC hdc = GetWindowDC(hParent); 199 | HFont = Tools::CreateFromSystemMessageFont(hdc, cFontSize); 200 | TxtHeight = Tools::GetFontHeight(hdc, HFont); 201 | ReleaseDC(hParent, hdc); 202 | } 203 | 204 | WindowList.push_back(this); 205 | int winNum = (int)WindowList.size(); 206 | 207 | HWND hWndTxt = CreateWindowEx(0, _T("STATIC"), text, 208 | WS_CHILD | WS_VISIBLE | SS_LEFT | SS_PATHELLIPSIS, 209 | 0, 0, 0, 0, _hWnd, NULL, HMod, NULL); 210 | 211 | adjustSizeAndPos(cWidth, TxtHeight + 25, winNum); 212 | 213 | RECT win; 214 | GetClientRect(_hWnd, &win); 215 | int width = win.right - win.left; 216 | int height = win.bottom - win.top; 217 | 218 | MoveWindow(hWndTxt, 5, 5, width - 95, TxtHeight, TRUE); 219 | 220 | HWND hPBar = CreateWindowEx(0, PROGRESS_CLASS, NULL, 221 | WS_CHILD | WS_VISIBLE | PBS_MARQUEE, 222 | 5, TxtHeight + 10, width - 95, 10, 223 | _hWnd, NULL, HMod, NULL); 224 | SendMessage(hPBar, PBM_SETMARQUEE, TRUE, 100); 225 | 226 | _hBtn = CreateWindowEx(0, _T("BUTTON"), _T("Cancel"), 227 | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 228 | width - 85, (height - 25) / 2, 80, 25, _hWnd, 229 | NULL, HMod, NULL); 230 | 231 | if (HFont) 232 | { 233 | SendMessage(hWndTxt, WM_SETFONT, (WPARAM)HFont, TRUE); 234 | SendMessage(_hBtn, WM_SETFONT, (WPARAM)HFont, TRUE); 235 | } 236 | 237 | ShowWindow(_hWnd, SW_SHOWNOACTIVATE); 238 | UpdateWindow(_hWnd); 239 | 240 | return _hWnd; 241 | } 242 | 243 | 244 | /** 245 | * \brief 246 | */ 247 | void ActivityWin::onResize(int winNum) 248 | { 249 | RECT win; 250 | GetClientRect(_hWnd, &win); 251 | adjustSizeAndPos(win.right - win.left, win.bottom - win.top, winNum); 252 | } 253 | 254 | 255 | /** 256 | * \brief 257 | */ 258 | LRESULT APIENTRY ActivityWin::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 259 | { 260 | switch (uMsg) 261 | { 262 | case WM_CREATE: 263 | { 264 | ActivityWin* aw = (ActivityWin*)((LPCREATESTRUCT)lParam)->lpCreateParams; 265 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(aw)); 266 | } 267 | return 0; 268 | 269 | case WM_SETFOCUS: 270 | { 271 | ActivityWin* aw = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 272 | SetFocus(aw->_hBtn); 273 | } 274 | return 0; 275 | 276 | case WM_CTLCOLORSTATIC: 277 | SetBkColor((HDC) wParam, GetSysColor(cBackgroundColor)); 278 | return (INT_PTR) GetSysColorBrush(cBackgroundColor); 279 | 280 | case WM_COMMAND: 281 | if (HIWORD(wParam) == BN_CLICKED) 282 | { 283 | ActivityWin* aw = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 284 | EnableWindow(aw->_hBtn, FALSE); 285 | SetEvent(aw->_hCancel); 286 | return 0; 287 | } 288 | break; 289 | 290 | case WM_DESTROY: 291 | { 292 | ActivityWin* aw = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 293 | delete aw; 294 | } 295 | return 0; 296 | } 297 | 298 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 299 | } 300 | 301 | } // namespace GTags 302 | -------------------------------------------------------------------------------- /src/ActivityWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Process Activity window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2015 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | namespace GTags 34 | { 35 | 36 | /** 37 | * \class ActivityWin 38 | * \brief 39 | */ 40 | class ActivityWin 41 | { 42 | public: 43 | static void Register(); 44 | static void Unregister(); 45 | 46 | static void Show(const TCHAR* text, HANDLE hCancel); 47 | static HWND GetHwnd(HANDLE hCancel); 48 | 49 | static void UpdatePositions(); 50 | 51 | private: 52 | static const TCHAR cClassName[]; 53 | static const int cBackgroundColor; 54 | static const unsigned cFontSize; 55 | static const int cWidth; 56 | 57 | static std::list WindowList; 58 | static HFONT HFont; 59 | static unsigned TxtHeight; 60 | 61 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 62 | 63 | ActivityWin(HANDLE hCancel) : _hCancel(hCancel), _hWnd(NULL) {} 64 | ActivityWin(const ActivityWin&); 65 | ~ActivityWin(); 66 | 67 | void adjustSizeAndPos(int width, int height, int winNum); 68 | HWND composeWindow(const TCHAR* text); 69 | void onResize(int winNum); 70 | 71 | HANDLE _hCancel; 72 | HWND _hWnd; 73 | HWND _hBtn; 74 | int _initRefCount; 75 | }; 76 | 77 | } // namespace GTags 78 | -------------------------------------------------------------------------------- /src/AutoCompleteWin.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags AutoComplete window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma comment (lib, "comctl32") 26 | 27 | 28 | #include 29 | #include 30 | #include "Common.h" 31 | #include "INpp.h" 32 | #include "GTags.h" 33 | #include "AutoCompleteWin.h" 34 | #include "Cmd.h" 35 | #include "LineParser.h" 36 | 37 | 38 | namespace GTags 39 | { 40 | 41 | const TCHAR AutoCompleteWin::cClassName[] = _T("AutoCompleteWin"); 42 | const int AutoCompleteWin::cBackgroundColor = COLOR_INFOBK; 43 | const int AutoCompleteWin::cWidth = 400; 44 | 45 | 46 | std::unique_ptr AutoCompleteWin::ACW {nullptr}; 47 | 48 | 49 | /** 50 | * \brief 51 | */ 52 | void AutoCompleteWin::Register() 53 | { 54 | WNDCLASS wc = {0}; 55 | wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; 56 | wc.lpfnWndProc = wndProc; 57 | wc.hInstance = HMod; 58 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 59 | wc.hbrBackground = GetSysColorBrush(cBackgroundColor); 60 | wc.lpszClassName = cClassName; 61 | 62 | RegisterClass(&wc); 63 | 64 | INITCOMMONCONTROLSEX icex = {0}; 65 | icex.dwSize = sizeof(icex); 66 | icex.dwICC = ICC_LISTVIEW_CLASSES; 67 | 68 | InitCommonControlsEx(&icex); 69 | } 70 | 71 | 72 | /** 73 | * \brief 74 | */ 75 | void AutoCompleteWin::Unregister() 76 | { 77 | UnregisterClass(cClassName, HMod); 78 | } 79 | 80 | 81 | /** 82 | * \brief 83 | */ 84 | void AutoCompleteWin::Show(const CmdPtr_t& cmd) 85 | { 86 | if (ACW) 87 | return; 88 | 89 | ACW = std::make_unique(cmd); 90 | 91 | if (ACW->composeWindow(cmd->Name()) == NULL) 92 | ACW = nullptr; 93 | } 94 | 95 | 96 | /** 97 | * \brief 98 | */ 99 | AutoCompleteWin::AutoCompleteWin(const CmdPtr_t& cmd) : 100 | _hWnd(NULL), _hLVWnd(NULL), _hFont(NULL), _cmdId(cmd->Id()), _ic(cmd->IgnoreCase()), 101 | _cmdTagLen((int)(_cmdId == AUTOCOMPLETE_FILE ? cmd->Tag().Len() - 1 : cmd->Tag().Len())), 102 | _completion(cmd->Parser()) 103 | {} 104 | 105 | 106 | /** 107 | * \brief 108 | */ 109 | AutoCompleteWin::~AutoCompleteWin() 110 | { 111 | INpp::Get().ClearSelectionMulti(); 112 | INpp::Get().EndUndoAction(); 113 | 114 | if (_hFont) 115 | DeleteObject(_hFont); 116 | } 117 | 118 | 119 | /** 120 | * \brief 121 | */ 122 | HWND AutoCompleteWin::composeWindow(const TCHAR* header) 123 | { 124 | HWND hOwner = INpp::Get().GetSciHandle(); 125 | RECT win; 126 | 127 | GetWindowRect(hOwner, &win); 128 | 129 | _hWnd = CreateWindow(cClassName, NULL, 130 | WS_POPUP | WS_BORDER, 131 | win.left, win.top, win.right - win.left, win.bottom - win.top, 132 | hOwner, NULL, HMod, NULL); 133 | if (_hWnd == NULL) 134 | return NULL; 135 | 136 | INpp::Get().RegisterWinForDarkMode(_hWnd); 137 | 138 | GetClientRect(_hWnd, &win); 139 | 140 | _hLVWnd = CreateWindow(WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | 141 | LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_NOSORTHEADER | LVS_SORTASCENDING, 142 | 0, 0, win.right - win.left, win.bottom - win.top, 143 | _hWnd, NULL, HMod, NULL); 144 | 145 | HDC hdc = GetWindowDC(_hLVWnd); 146 | 147 | _hFont = CreateFont( 148 | -MulDiv(UIFontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72), 149 | 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 150 | OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 151 | FF_DONTCARE | DEFAULT_PITCH, UIFontName.C_str()); 152 | 153 | ReleaseDC(_hLVWnd, hdc); 154 | 155 | if (_hFont) 156 | SendMessage(_hLVWnd, WM_SETFONT, (WPARAM)_hFont, TRUE); 157 | 158 | ListView_SetExtendedListViewStyle(_hLVWnd, LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); 159 | 160 | TCHAR buf[32]; 161 | _tcscpy_s(buf, _countof(buf), header); 162 | 163 | LVCOLUMN lvCol = {0}; 164 | lvCol.mask = LVCF_TEXT | LVCF_WIDTH; 165 | lvCol.pszText = buf; 166 | lvCol.cchTextMax = _countof(buf); 167 | lvCol.cx = cWidth; 168 | ListView_InsertColumn(_hLVWnd, 0, &lvCol); 169 | 170 | DWORD backgroundColor = GetSysColor(cBackgroundColor); 171 | ListView_SetBkColor(_hLVWnd, backgroundColor); 172 | ListView_SetTextBkColor(_hLVWnd, backgroundColor); 173 | 174 | CTextA wordA; 175 | INpp::Get().GetWord(wordA, true, true, true); 176 | CText word(wordA.C_str()); 177 | 178 | if (!filterLV(word)) 179 | { 180 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 181 | return NULL; 182 | } 183 | 184 | resizeLV(); 185 | 186 | ShowWindow(_hWnd, SW_SHOWNORMAL); 187 | UpdateWindow(_hWnd); 188 | 189 | INpp::Get().BeginUndoAction(); 190 | 191 | return _hWnd; 192 | } 193 | 194 | 195 | /** 196 | * \brief 197 | */ 198 | int AutoCompleteWin::filterLV(const CText& filter) 199 | { 200 | LVITEM lvItem = {0}; 201 | lvItem.mask = LVIF_TEXT | LVIF_STATE; 202 | 203 | size_t len = filter.Len(); 204 | 205 | ListView_DeleteAllItems(_hLVWnd); 206 | 207 | int (*pCompare)(const TCHAR*, const TCHAR*, size_t); 208 | 209 | if (_ic) 210 | pCompare = &_tcsnicmp; 211 | else 212 | pCompare = &_tcsncmp; 213 | 214 | for (const auto& complEntry : _completion->GetList()) 215 | { 216 | if (!len || !pCompare(complEntry, filter.C_str(), len)) 217 | { 218 | lvItem.pszText = complEntry; 219 | ListView_InsertItem(_hLVWnd, &lvItem); 220 | ++lvItem.iItem; 221 | } 222 | } 223 | 224 | if (lvItem.iItem > 0) 225 | ListView_SetItemState(_hLVWnd, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); 226 | 227 | return lvItem.iItem; 228 | } 229 | 230 | 231 | /** 232 | * \brief 233 | */ 234 | void AutoCompleteWin::resizeLV() 235 | { 236 | bool scroll = false; 237 | int rowsCount = ListView_GetItemCount(_hLVWnd); 238 | if (rowsCount > 7) 239 | { 240 | rowsCount = 7; 241 | scroll = true; 242 | } 243 | 244 | RECT win; 245 | ListView_GetItemRect(_hLVWnd, 0, &win, LVIR_BOUNDS); 246 | int lvWidth = win.right - win.left; 247 | int lvHeight = (win.bottom - win.top) * rowsCount; 248 | 249 | HWND hHeader = ListView_GetHeader(_hLVWnd); 250 | GetWindowRect(hHeader, &win); 251 | lvHeight += win.bottom - win.top; 252 | 253 | RECT maxWin; 254 | INpp& npp = INpp::Get(); 255 | GetWindowRect(npp.GetSciHandle(), &maxWin); 256 | 257 | int maxWidth = (maxWin.right - maxWin.left) - 30; 258 | if (scroll) 259 | maxWidth -= GetSystemMetrics(SM_CXVSCROLL); 260 | if (lvWidth > maxWidth) 261 | lvWidth = maxWidth; 262 | 263 | ListView_SetColumnWidth(_hLVWnd, 0, lvWidth); 264 | 265 | if (scroll) 266 | lvWidth += GetSystemMetrics(SM_CXVSCROLL); 267 | 268 | win.left = maxWin.left; 269 | win.top = maxWin.top; 270 | win.right = win.left + lvWidth; 271 | win.bottom = win.top + lvHeight; 272 | 273 | AdjustWindowRect(&win, (DWORD)GetWindowLongPtr(_hWnd, GWL_STYLE), FALSE); 274 | lvWidth = win.right - win.left; 275 | lvHeight = win.bottom - win.top; 276 | 277 | int xOffset, yOffset; 278 | npp.GetPointPos(&xOffset, &yOffset); 279 | 280 | win.left = maxWin.left + xOffset; 281 | win.top = maxWin.top + yOffset + npp.GetTextHeight(); 282 | win.right = win.left + lvWidth; 283 | win.bottom = win.top + lvHeight; 284 | 285 | xOffset = win.right - maxWin.right; 286 | if (xOffset > 0) 287 | { 288 | win.left -= xOffset; 289 | win.right -= xOffset; 290 | } 291 | 292 | if (win.bottom > maxWin.bottom) 293 | { 294 | win.bottom = maxWin.top + yOffset; 295 | win.top = win.bottom - lvHeight; 296 | } 297 | 298 | MoveWindow(_hWnd, win.left, win.top, win.right - win.left, win.bottom - win.top, TRUE); 299 | 300 | GetClientRect(_hWnd, &win); 301 | MoveWindow(_hLVWnd, 0, 0, win.right - win.left, win.bottom - win.top, TRUE); 302 | } 303 | 304 | 305 | /** 306 | * \brief 307 | */ 308 | void AutoCompleteWin::onDblClick() 309 | { 310 | TCHAR itemTxt[MAX_PATH]; 311 | LVITEM lvItem = {0}; 312 | lvItem.mask = LVIF_TEXT; 313 | lvItem.iItem = ListView_GetNextItem(_hLVWnd, -1, LVNI_SELECTED); 314 | lvItem.pszText = itemTxt; 315 | lvItem.cchTextMax = _countof(itemTxt); 316 | 317 | ListView_GetItem(_hLVWnd, &lvItem); 318 | lvItem.pszText[lvItem.cchTextMax - 1] = 0; 319 | 320 | CTextA completion(itemTxt); 321 | INpp::Get().ReplaceWordMulti(completion.C_str(), true); 322 | 323 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 324 | } 325 | 326 | 327 | /** 328 | * \brief 329 | */ 330 | bool AutoCompleteWin::onKeyDown(int keyCode) 331 | { 332 | switch (keyCode) 333 | { 334 | case VK_UP: 335 | case VK_DOWN: 336 | return false; 337 | 338 | case VK_TAB: 339 | case VK_RETURN: 340 | onDblClick(); 341 | return true; 342 | 343 | case VK_LEFT: 344 | case VK_RIGHT: 345 | case VK_ESCAPE: 346 | case VK_CONTROL: 347 | case VK_MENU: 348 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 349 | return true; 350 | 351 | case VK_DELETE: 352 | INpp::Get().ReplaceWordMulti("", true); 353 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 354 | return true; 355 | 356 | case VK_BACK: 357 | { 358 | INpp& npp = INpp::Get(); 359 | npp.ClearSelectionMulti(); 360 | npp.Backspace(); 361 | if (npp.GetWordSize(true) < _cmdTagLen) 362 | { 363 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 364 | return true; 365 | } 366 | } 367 | break; 368 | 369 | default: 370 | { 371 | BYTE keysState[256]; 372 | WORD character; 373 | 374 | if (!GetKeyboardState(keysState)) 375 | return false; 376 | if (ToAscii(keyCode, MapVirtualKey(keyCode, MAPVK_VK_TO_VSC), keysState, &character, 1) != 1) 377 | return false; 378 | 379 | INpp& npp = INpp::Get(); 380 | 381 | if (npp.GetSelectionsCount() == 1) 382 | { 383 | npp.AddText((char*)&character, 1); 384 | } 385 | else 386 | { 387 | const char charStr[] {(char)character, '\0'}; 388 | npp.InsertTextAtMultiPos(charStr); 389 | } 390 | 391 | if (keyCode == VK_SPACE) 392 | { 393 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 394 | return true; 395 | } 396 | } 397 | } 398 | 399 | if (!INpp::Get().IsPreviousCharWordEnd()) 400 | { 401 | CTextA wordA; 402 | INpp::Get().GetWord(wordA, true, true, true); 403 | CText word(wordA.C_str()); 404 | int lvItemsCnt = filterLV(word); 405 | 406 | if (lvItemsCnt == 0) 407 | { 408 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 409 | } 410 | else if (lvItemsCnt == 1) 411 | { 412 | TCHAR itemTxt[MAX_PATH]; 413 | LVITEM lvItem = {0}; 414 | lvItem.mask = LVIF_TEXT; 415 | lvItem.iItem = ListView_GetNextItem(_hLVWnd, -1, LVNI_SELECTED); 416 | lvItem.pszText = itemTxt; 417 | lvItem.cchTextMax = _countof(itemTxt); 418 | 419 | ListView_GetItem(_hLVWnd, &lvItem); 420 | lvItem.pszText[lvItem.cchTextMax - 1] = 0; 421 | 422 | if (!_tcscmp(word.C_str(), lvItem.pszText)) 423 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 424 | } 425 | } 426 | else 427 | { 428 | SendMessage(_hWnd, WM_CLOSE, 0, 0); 429 | } 430 | 431 | return true; 432 | } 433 | 434 | 435 | /** 436 | * \brief 437 | */ 438 | LRESULT APIENTRY AutoCompleteWin::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 439 | { 440 | switch (uMsg) 441 | { 442 | case WM_CREATE: 443 | return 0; 444 | 445 | case WM_SETFOCUS: 446 | SetFocus(ACW->_hLVWnd); 447 | return 0; 448 | 449 | case WM_NOTIFY: 450 | switch (((LPNMHDR)lParam)->code) 451 | { 452 | case NM_KILLFOCUS: 453 | SendMessage(hWnd, WM_CLOSE, 0, 0); 454 | return 0; 455 | 456 | case LVN_KEYDOWN: 457 | if (ACW->onKeyDown(((LPNMLVKEYDOWN)lParam)->wVKey)) 458 | return 1; 459 | break; 460 | 461 | case NM_DBLCLK: 462 | ACW->onDblClick(); 463 | return 0; 464 | } 465 | break; 466 | 467 | case WM_DESTROY: 468 | ACW = nullptr; 469 | return 0; 470 | } 471 | 472 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 473 | } 474 | 475 | } // namespace GTags 476 | -------------------------------------------------------------------------------- /src/AutoCompleteWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags AutoComplete window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | #include "CmdDefines.h" 33 | 34 | 35 | namespace GTags 36 | { 37 | 38 | /** 39 | * \class AutoCompleteWin 40 | * \brief 41 | */ 42 | class AutoCompleteWin 43 | { 44 | public: 45 | static void Register(); 46 | static void Unregister(); 47 | 48 | static void Show(const CmdPtr_t& cmd); 49 | 50 | static bool IsShown() 51 | { 52 | return (ACW != nullptr); 53 | } 54 | 55 | AutoCompleteWin(const CmdPtr_t& cmd); 56 | AutoCompleteWin(const AutoCompleteWin&); 57 | ~AutoCompleteWin(); 58 | 59 | private: 60 | static const TCHAR cClassName[]; 61 | static const int cBackgroundColor; 62 | static const int cWidth; 63 | 64 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 65 | 66 | AutoCompleteWin& operator=(const AutoCompleteWin&) = delete; 67 | 68 | HWND composeWindow(const TCHAR* header); 69 | int filterLV(const CText& filter); 70 | void resizeLV(); 71 | 72 | void onDblClick(); 73 | bool onKeyDown(int keyCode); 74 | 75 | static std::unique_ptr ACW; 76 | 77 | HWND _hWnd; 78 | HWND _hLVWnd; 79 | HFONT _hFont; 80 | const CmdId_t _cmdId; 81 | const bool _ic; 82 | const int _cmdTagLen; 83 | ParserPtr_t _completion; 84 | }; 85 | 86 | } // namespace GTags 87 | -------------------------------------------------------------------------------- /src/AutoLock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Provides locking classes for abstraction and convenience 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2015 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | 30 | 31 | #define AUTOLOCK(x) AutoLock __lock_obj(x) 32 | #define IF_AUTO_TRYLOCK_FAIL(x) AutoTryLock __lock_obj(x); \ 33 | if (!__lock_obj.IsLocked()) 34 | 35 | 36 | /** 37 | * \class Mutex 38 | * \brief 39 | */ 40 | class Mutex 41 | { 42 | public: 43 | Mutex() 44 | { 45 | InitializeCriticalSectionAndSpinCount(&_lock, 1024); 46 | } 47 | 48 | ~Mutex() 49 | { 50 | DeleteCriticalSection(&_lock); 51 | } 52 | 53 | inline void Lock() 54 | { 55 | EnterCriticalSection(&_lock); 56 | } 57 | 58 | inline BOOL TryLock() 59 | { 60 | return TryEnterCriticalSection(&_lock); 61 | } 62 | 63 | inline void Unlock() 64 | { 65 | LeaveCriticalSection(&_lock); 66 | } 67 | 68 | private: 69 | CRITICAL_SECTION _lock; 70 | }; 71 | 72 | 73 | /** 74 | * \class AutoLock 75 | * \brief 76 | */ 77 | class AutoLock 78 | { 79 | public: 80 | AutoLock(Mutex& lock) : _lock(lock) 81 | { 82 | _lock.Lock(); 83 | } 84 | 85 | ~AutoLock() 86 | { 87 | _lock.Unlock(); 88 | } 89 | 90 | private: 91 | Mutex& _lock; 92 | }; 93 | 94 | 95 | /** 96 | * \class AutoTryLock 97 | * \brief 98 | */ 99 | class AutoTryLock 100 | { 101 | public: 102 | AutoTryLock(Mutex& lock) : _lock(lock) 103 | { 104 | _isLocked = _lock.TryLock(); 105 | } 106 | 107 | ~AutoTryLock() 108 | { 109 | if (_isLocked) 110 | _lock.Unlock(); 111 | } 112 | 113 | BOOL IsLocked() { return _isLocked; } 114 | 115 | private: 116 | Mutex& _lock; 117 | BOOL _isLocked; 118 | }; 119 | -------------------------------------------------------------------------------- /src/Cmd.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags command class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2022 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include "Cmd.h" 26 | 27 | 28 | namespace GTags 29 | { 30 | 31 | const TCHAR* Cmd::CmdName[] = { 32 | _T("Create Database"), // CREATE_DATABASE 33 | _T("Database Single File Update"), // UPDATE_SINGLE 34 | _T("AutoComplete"), // AUTOCOMPLETE 35 | _T("AutoComplete"), // AUTOCOMPLETE_SYMBOL 36 | _T("AutoComplete File Name"), // AUTOCOMPLETE_FILE 37 | _T("Find File"), // FIND_FILE 38 | _T("Find Definition"), // FIND_DEFINITION 39 | _T("Find Reference"), // FIND_REFERENCE 40 | _T("Find Symbol"), // FIND_SYMBOL 41 | _T("Search in Source Files"), // GREP 42 | _T("Search in Other Files"), // GREP_TEXT 43 | _T("About"), // VERSION 44 | _T("About CTags") // CTAGS_VERSION 45 | }; 46 | 47 | 48 | /** 49 | * \brief 50 | */ 51 | Cmd::Cmd(CmdId_t id, DbHandle db, ParserPtr_t parser, 52 | const TCHAR* tag, bool ignoreCase, bool regExp, bool autorun) : 53 | _id(id), _db(db), _parser(parser), 54 | _ignoreCase(ignoreCase), _regExp(regExp), _autorun(autorun), _skipLibs(false), _status(CANCELLED) 55 | { 56 | if (tag) 57 | _tag = tag; 58 | } 59 | 60 | 61 | void Cmd::AppendToResult(const std::vector& data) 62 | { 63 | // remove \0 string termination 64 | if (!_result.empty()) 65 | _result.pop_back(); 66 | _result.insert(_result.cend(), data.begin(), data.end()); 67 | } 68 | 69 | } // namespace GTags 70 | -------------------------------------------------------------------------------- /src/Cmd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags command class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "Common.h" 33 | #include "CmdDefines.h" 34 | #include "DbManager.h" 35 | 36 | 37 | namespace GTags 38 | { 39 | 40 | class CmdEngine; 41 | 42 | 43 | /** 44 | * \class ResultParser 45 | * \brief 46 | */ 47 | class ResultParser 48 | { 49 | public: 50 | virtual ~ResultParser() {} 51 | 52 | virtual intptr_t Parse(const CmdPtr_t&) = 0; 53 | virtual const CTextA& GetText() const { return _buf; } 54 | virtual const std::vector& GetList() const { return _lines; } 55 | 56 | protected: 57 | CTextA _buf; 58 | std::vector _lines; 59 | }; 60 | 61 | 62 | /** 63 | * \class Cmd 64 | * \brief 65 | */ 66 | class Cmd 67 | { 68 | public: 69 | static const TCHAR* CmdName[]; 70 | 71 | Cmd(CmdId_t id, DbHandle db = NULL, ParserPtr_t parser = ParserPtr_t(NULL), 72 | const TCHAR* tag = NULL, bool ignoreCase = false, bool regExp = false, bool autorun = false); 73 | ~Cmd() {} 74 | 75 | inline void Id(CmdId_t id) { _id = id; } 76 | inline CmdId_t Id() const { return _id; } 77 | 78 | inline const TCHAR* Name() const { return CmdName[_id]; } 79 | 80 | inline DbHandle Db() const { return _db; } 81 | 82 | inline void Tag(const CText& tag) { _tag = tag; } 83 | inline const CText& Tag() const { return _tag; } 84 | 85 | inline void Parser(const ParserPtr_t& parser) { _parser = parser; } 86 | inline const ParserPtr_t& Parser() const { return _parser; } 87 | 88 | inline void RegExp(bool re) { _regExp = re; } 89 | inline bool RegExp() const { return _regExp; } 90 | 91 | inline void IgnoreCase(bool ic) { _ignoreCase = ic; } 92 | inline bool IgnoreCase() const { return _ignoreCase; } 93 | 94 | inline bool IsAutorun() const { return _autorun; } 95 | 96 | inline void SkipLibs(bool skipLibs) { _skipLibs = skipLibs; } 97 | inline bool SkipLibs() const { return _skipLibs; } 98 | 99 | inline void Status(CmdStatus_t stat) { _status = stat; } 100 | inline CmdStatus_t Status() const { return _status; } 101 | 102 | inline char* Result() { return _result.data(); } 103 | inline const char* Result() const { return _result.data(); } 104 | inline size_t ResultLen() const { return _result.size() - 1; } 105 | 106 | void AppendToResult(const std::vector& data); 107 | void SetResult(const std::vector& data) 108 | { 109 | _result.assign(data.begin(), data.end()); 110 | } 111 | 112 | private: 113 | friend class CmdEngine; 114 | 115 | CmdId_t _id; 116 | DbHandle _db; 117 | 118 | CText _tag; 119 | ParserPtr_t _parser; 120 | bool _ignoreCase; 121 | bool _regExp; 122 | bool _autorun; // Used only for AutoComplete command to distinguish between auto and manual run 123 | bool _skipLibs; 124 | 125 | CmdStatus_t _status; 126 | std::vector _result; 127 | }; 128 | 129 | } // namespace GTags 130 | -------------------------------------------------------------------------------- /src/CmdDefines.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags command forward declarations 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | 30 | 31 | namespace GTags 32 | { 33 | 34 | enum CmdId_t 35 | { 36 | CREATE_DATABASE = 0, 37 | UPDATE_SINGLE, 38 | AUTOCOMPLETE, 39 | AUTOCOMPLETE_SYMBOL, 40 | AUTOCOMPLETE_FILE, 41 | FIND_FILE, 42 | FIND_DEFINITION, 43 | FIND_REFERENCE, 44 | FIND_SYMBOL, 45 | GREP, 46 | GREP_TEXT, 47 | VERSION, 48 | CTAGS_VERSION 49 | }; 50 | 51 | 52 | enum CmdStatus_t 53 | { 54 | CANCELLED = 0, 55 | RUN_ERROR, 56 | FAILED, 57 | PARSE_ERROR, 58 | PARSE_EMPTY, 59 | OK 60 | }; 61 | 62 | 63 | class Cmd; 64 | class ResultParser; 65 | 66 | 67 | typedef std::shared_ptr CmdPtr_t; 68 | typedef std::shared_ptr ParserPtr_t; 69 | typedef void (*CompletionCB)(const CmdPtr_t&); 70 | 71 | } // namespace GTags 72 | -------------------------------------------------------------------------------- /src/CmdEngine.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags command execution engine 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include "Common.h" 29 | #include "INpp.h" 30 | #include "Config.h" 31 | #include "GTags.h" 32 | #include "ReadPipe.h" 33 | #include "CmdEngine.h" 34 | #include "Cmd.h" 35 | 36 | 37 | namespace GTags 38 | { 39 | 40 | const TCHAR* CmdEngine::CmdLine[] = { 41 | _T("\"%s\\gtags.exe\" -c --skip-unreadable"), // CREATE_DATABASE 42 | _T("\"%s\\gtags.exe\" -c --skip-unreadable --single-update \"%s\""), // UPDATE_SINGLE 43 | _T("\"%s\\global.exe\" -cT \"%s\""), // AUTOCOMPLETE 44 | _T("\"%s\\global.exe\" -cs \"%s\""), // AUTOCOMPLETE_SYMBOL 45 | _T("\"%s\\global.exe\" -cPo --match-part=all \"%s\""), // AUTOCOMPLETE_FILE 46 | _T("\"%s\\global.exe\" -Po \"%s\""), // FIND_FILE 47 | _T("\"%s\\global.exe\" -dT --result=grep --path-style=abslib \"%s\""), // FIND_DEFINITION 48 | _T("\"%s\\global.exe\" -r --result=grep \"%s\""), // FIND_REFERENCE 49 | _T("\"%s\\global.exe\" -s --result=grep \"%s\""), // FIND_SYMBOL 50 | _T("\"%s\\global.exe\" -g --result=grep \"%s\""), // GREP 51 | _T("\"%s\\global.exe\" -gO --result=grep \"%s\""), // GREP_TEXT 52 | _T("\"%s\\global.exe\" --version"), // VERSION 53 | _T("\"%s\\ctags.exe\" --version") // CTAGS_VERSION 54 | }; 55 | 56 | 57 | /** 58 | * \brief 59 | */ 60 | bool CmdEngine::Run(const CmdPtr_t& cmd, CompletionCB complCB) 61 | { 62 | if (!complCB) 63 | return false; 64 | 65 | CmdEngine* engine = new CmdEngine(cmd, complCB); 66 | cmd->Status(RUN_ERROR); 67 | 68 | engine->_hThread = (HANDLE)_beginthreadex(NULL, 0, threadFunc, engine, 0, NULL); 69 | if (engine->_hThread == NULL) 70 | { 71 | delete engine; 72 | return false; 73 | } 74 | 75 | return true; 76 | } 77 | 78 | 79 | /** 80 | * \brief 81 | */ 82 | CmdEngine::CmdEngine(const CmdPtr_t& cmd, CompletionCB complCB) : 83 | _cmd(cmd), _complCB(complCB), _hThread(NULL) 84 | { 85 | } 86 | 87 | 88 | /** 89 | * \brief 90 | */ 91 | CmdEngine::~CmdEngine() 92 | { 93 | SendMessage(MainWndH, WM_RUN_CMD_CALLBACK, (WPARAM)_complCB, (LPARAM)(&_cmd)); 94 | 95 | if (_hThread) 96 | CloseHandle(_hThread); 97 | } 98 | 99 | 100 | /** 101 | * \brief 102 | */ 103 | unsigned __stdcall CmdEngine::threadFunc(void* data) 104 | { 105 | CmdEngine* engine = static_cast(data); 106 | unsigned r = engine->start(); 107 | 108 | delete engine; 109 | 110 | return r; 111 | } 112 | 113 | 114 | /** 115 | * \brief 116 | */ 117 | unsigned CmdEngine::start() 118 | { 119 | ReadPipe dataPipe; 120 | ReadPipe errorPipe; 121 | 122 | PROCESS_INFORMATION pi; 123 | 124 | if (!runProcess(pi, dataPipe, errorPipe)) 125 | return 1; 126 | 127 | bool showActivityWin = true; 128 | if (_cmd->_id != CREATE_DATABASE && _cmd->_id != UPDATE_SINGLE) 129 | { 130 | // Wait 300 ms and if process has finished don't show Activity Window 131 | if (WaitForSingleObject(pi.hProcess, 300) == WAIT_OBJECT_0) 132 | showActivityWin = false; 133 | } 134 | 135 | if (showActivityWin) 136 | { 137 | HANDLE hCancel = CreateEvent(NULL, TRUE, FALSE, NULL); 138 | 139 | if (hCancel) 140 | { 141 | CText header(_cmd->Name()); 142 | 143 | if (_cmd->_id != VERSION && _cmd->_id != CTAGS_VERSION) 144 | { 145 | header += _T(" - \""); 146 | if (_cmd->_id == CREATE_DATABASE) 147 | header += _cmd->Db()->GetPath(); 148 | else 149 | header += _cmd->Tag(); 150 | header += _T('\"'); 151 | } 152 | 153 | SendMessage(MainWndH, WM_OPEN_ACTIVITY_WIN, 154 | reinterpret_cast(header.C_str()), reinterpret_cast(hCancel)); 155 | 156 | HANDLE waitHandles[] = {pi.hProcess, hCancel}; 157 | DWORD handleId = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE) - WAIT_OBJECT_0; 158 | if (handleId > 0 && handleId < 2 && waitHandles[handleId] == hCancel) 159 | _cmd->_status = CANCELLED; 160 | 161 | SendMessage(MainWndH, WM_CLOSE_ACTIVITY_WIN, 0, reinterpret_cast(hCancel)); 162 | 163 | CloseHandle(hCancel); 164 | } 165 | else 166 | { 167 | WaitForSingleObject(pi.hProcess, INFINITE); 168 | } 169 | } 170 | 171 | endProcess(pi); 172 | 173 | if (_cmd->_status == CANCELLED) 174 | return 1; 175 | 176 | if (!dataPipe.GetOutput().empty()) 177 | { 178 | _cmd->AppendToResult(dataPipe.GetOutput()); 179 | } 180 | else if (!errorPipe.GetOutput().empty()) 181 | { 182 | if (_cmd->_id != CREATE_DATABASE && _cmd->_id != UPDATE_SINGLE) 183 | { 184 | _cmd->SetResult(errorPipe.GetOutput()); 185 | _cmd->_status = FAILED; 186 | return 1; 187 | } 188 | 189 | if (_cmd->_id == CREATE_DATABASE) 190 | _cmd->SetResult(errorPipe.GetOutput()); 191 | } 192 | 193 | _cmd->_status = OK; 194 | 195 | if (_cmd->_parser) 196 | { 197 | if (_cmd->Result()) 198 | { 199 | const intptr_t parsedEntries = _cmd->_parser->Parse(_cmd); 200 | 201 | if (parsedEntries < 0) 202 | { 203 | _cmd->_status = PARSE_ERROR; 204 | return 1; 205 | } 206 | else if (parsedEntries == 0) 207 | { 208 | _cmd->_status = PARSE_EMPTY; // No results to display actually (due to some filtering) 209 | return 1; 210 | } 211 | } 212 | // Blink the auto-complete word to inform the user if nothing is found 213 | else if (_cmd->_id == AUTOCOMPLETE_FILE || 214 | ((_cmd->_id == AUTOCOMPLETE || _cmd->_id == AUTOCOMPLETE_SYMBOL) && !_cmd->_autorun)) 215 | { 216 | CTextA wordA; 217 | INpp::Get().GetWord(wordA, true, true); 218 | 219 | if (wordA.Len()) 220 | { 221 | CText word(wordA.C_str()); 222 | 223 | TCHAR* tag = _cmd->_tag.C_str(); 224 | size_t len = _cmd->_tag.Len(); 225 | if (_cmd->_id == AUTOCOMPLETE_FILE) 226 | { 227 | ++tag; 228 | --len; 229 | } 230 | 231 | if (!_tcsncmp(word.C_str(), tag, len)) 232 | Sleep(50); 233 | } 234 | } 235 | } 236 | 237 | if (_cmd->_id == CREATE_DATABASE) 238 | _cmd->Db()->SaveCfg(); 239 | 240 | return 0; 241 | } 242 | 243 | 244 | /** 245 | * \brief 246 | */ 247 | void CmdEngine::composeCmd(CText& buf) const 248 | { 249 | CPath path(DllPath); 250 | path.StripFilename(); 251 | path += cBinariesFolder; 252 | 253 | buf.Resize(2048); 254 | 255 | if (_cmd->_id == CREATE_DATABASE || _cmd->_id == VERSION || _cmd->_id == CTAGS_VERSION) 256 | _sntprintf_s(buf.C_str(), buf.Size(), _TRUNCATE, CmdLine[_cmd->_id], path.C_str()); 257 | else 258 | _sntprintf_s(buf.C_str(), buf.Size(), _TRUNCATE, CmdLine[_cmd->_id], path.C_str(), 259 | _cmd->Tag().C_str()); 260 | 261 | if (_cmd->_id == CREATE_DATABASE || _cmd->_id == UPDATE_SINGLE) 262 | { 263 | path += _T("\\gtags.conf"); 264 | if (path.FileExists()) 265 | { 266 | buf += _T(" --gtagsconf \""); 267 | buf += path; 268 | buf += _T("\""); 269 | buf += _T(" --gtagslabel="); 270 | buf += _cmd->Db()->GetConfig().Parser(); 271 | } 272 | } 273 | else if (_cmd->_id != VERSION && _cmd->_id != CTAGS_VERSION) 274 | { 275 | if (_cmd->_ignoreCase) 276 | buf += _T(" -i"); 277 | else 278 | buf += _T(" -M"); 279 | 280 | if (!_cmd->_regExp) 281 | buf += _T(" --literal"); 282 | } 283 | } 284 | 285 | 286 | /** 287 | * \brief 288 | */ 289 | void CmdEngine::setEnvironmentVars() const 290 | { 291 | CText buf; 292 | 293 | if (!_cmd->_skipLibs && (_cmd->_id == AUTOCOMPLETE || _cmd->_id == FIND_DEFINITION)) 294 | { 295 | const DbConfig& cfg = _cmd->Db()->GetConfig(); 296 | if (cfg._useLibDb && cfg._libDbPaths.size()) 297 | { 298 | if (!cfg._libDbPaths[0].IsSubpathOf(_cmd->Db()->GetPath())) 299 | buf += cfg._libDbPaths[0]; 300 | 301 | for (size_t i = 1; i < cfg._libDbPaths.size(); ++i) 302 | { 303 | if (!cfg._libDbPaths[i].IsSubpathOf(_cmd->Db()->GetPath())) 304 | { 305 | buf += _T(';'); 306 | buf += cfg._libDbPaths[i]; 307 | } 308 | } 309 | } 310 | } 311 | 312 | if (_cmd->Db()) 313 | SetEnvironmentVariable(_T("GTAGSDBPATH"), _cmd->Db()->GetPath().C_str()); 314 | 315 | SetEnvironmentVariable(_T("GTAGSLIBPATH"), buf.C_str()); 316 | } 317 | 318 | 319 | /** 320 | * \brief 321 | */ 322 | bool CmdEngine::runProcess(PROCESS_INFORMATION& pi, ReadPipe& dataPipe, ReadPipe& errorPipe) 323 | { 324 | const DWORD createFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; 325 | const TCHAR* currentDir = (_cmd->_id == VERSION || _cmd->_id == CTAGS_VERSION) ? 326 | NULL : _cmd->Db()->GetPath().C_str(); 327 | 328 | CText cmdBuf; 329 | composeCmd(cmdBuf); 330 | 331 | setEnvironmentVars(); 332 | 333 | STARTUPINFO si = {0}; 334 | si.cb = sizeof(si); 335 | si.dwFlags = STARTF_USESTDHANDLES; 336 | si.hStdError = errorPipe.GetInputHandle(); 337 | si.hStdOutput = dataPipe.GetInputHandle(); 338 | 339 | if (!CreateProcess(NULL, cmdBuf.C_str(), NULL, NULL, TRUE, createFlags, NULL, currentDir, &si, &pi)) 340 | { 341 | _cmd->_status = RUN_ERROR; 342 | return false; 343 | } 344 | 345 | SetThreadPriority(pi.hThread, THREAD_PRIORITY_NORMAL); 346 | 347 | if (!errorPipe.Open() || !dataPipe.Open()) 348 | { 349 | endProcess(pi); 350 | _cmd->_status = RUN_ERROR; 351 | return false; 352 | } 353 | 354 | return true; 355 | } 356 | 357 | 358 | /** 359 | * \brief 360 | */ 361 | void CmdEngine::endProcess(PROCESS_INFORMATION& pi) 362 | { 363 | DWORD r; 364 | GetExitCodeProcess(pi.hProcess, &r); 365 | if (r == STILL_ACTIVE) 366 | TerminateProcess(pi.hProcess, 0); 367 | 368 | CloseHandle(pi.hThread); 369 | CloseHandle(pi.hProcess); 370 | } 371 | 372 | } // namespace GTags 373 | -------------------------------------------------------------------------------- /src/CmdEngine.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags command execution engine 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2022 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include "Common.h" 31 | #include "CmdDefines.h" 32 | 33 | 34 | class ReadPipe; 35 | 36 | 37 | namespace GTags 38 | { 39 | 40 | /** 41 | * \class CmdEngine 42 | * \brief 43 | */ 44 | class CmdEngine 45 | { 46 | public: 47 | static bool Run(const CmdPtr_t& cmd, CompletionCB complCB); 48 | 49 | private: 50 | static const TCHAR* CmdLine[]; 51 | 52 | static unsigned __stdcall threadFunc(void* data); 53 | 54 | CmdEngine(const CmdPtr_t& cmd, CompletionCB complCB); 55 | ~CmdEngine(); 56 | CmdEngine& operator=(const CmdEngine&) = delete; 57 | 58 | unsigned start(); 59 | void composeCmd(CText& buf) const; 60 | void setEnvironmentVars() const; 61 | bool runProcess(PROCESS_INFORMATION& pi, ReadPipe& dataPipe, ReadPipe& errorPipe); 62 | void endProcess(PROCESS_INFORMATION& pi); 63 | 64 | CmdPtr_t _cmd; 65 | CompletionCB const _complCB; 66 | HANDLE _hThread; 67 | }; 68 | 69 | } // namespace GTags 70 | -------------------------------------------------------------------------------- /src/Common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Various helper types and functions 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | #ifdef UNICODE 36 | #define CText CTextW 37 | #else 38 | #define CText CTextA 39 | #endif 40 | 41 | 42 | /** 43 | * \class CTextW 44 | * \brief 45 | */ 46 | class CTextW 47 | { 48 | protected: 49 | std::vector _buf; 50 | bool _invalidStrLen; 51 | 52 | public: 53 | CTextW() : _invalidStrLen(false) { _buf.push_back(0); } 54 | CTextW(size_t size) : _invalidStrLen(true) { _buf.resize(size + 1, 0); } 55 | 56 | CTextW(const wchar_t* str); 57 | CTextW(const char* str); 58 | 59 | CTextW(const CTextW& txt) : _buf(txt._buf), _invalidStrLen(txt._invalidStrLen) {} 60 | 61 | ~CTextW() {} 62 | 63 | inline void AutoFit() 64 | { 65 | if (_invalidStrLen) 66 | { 67 | _buf.resize(wcslen(_buf.data()) + 1, 0); 68 | _invalidStrLen = false; 69 | } 70 | } 71 | 72 | CTextW& operator=(const CTextW& txt); 73 | CTextW& operator=(const wchar_t* str); 74 | CTextW& operator=(const char* str); 75 | 76 | inline bool operator==(const CTextW& txt) const { return (_buf == txt._buf); } 77 | inline bool operator==(const wchar_t* str) const { return !wcscmp(_buf.data(), str); } 78 | inline bool operator!=(const CTextW& txt) const { return !(*this == txt); } 79 | inline bool operator!=(const char* str) const { return !(*this == str); } 80 | 81 | void operator+=(const CTextW& txt); 82 | void operator+=(const wchar_t* str); 83 | void operator+=(const char* str); 84 | void operator+=(wchar_t letter); 85 | 86 | void Append(const wchar_t* data, size_t len); 87 | void Append(const char* data, size_t len); 88 | void Insert(size_t at_pos, wchar_t letter); 89 | void Insert(size_t at_pos, const wchar_t* data, size_t len); 90 | void Erase(size_t from_pos, size_t len); 91 | 92 | void Clear(); 93 | void Resize(size_t size); 94 | 95 | inline size_t Len() const { return (_invalidStrLen) ? wcslen(_buf.data()) : (_buf.size() - 1); } 96 | inline bool IsEmpty() const { return (Len() == 0); } 97 | inline const std::vector& Vector() const { return _buf; } 98 | inline const wchar_t* C_str() const { return _buf.data(); } 99 | inline wchar_t* C_str() { return _buf.data(); } 100 | inline size_t Size() const { return _buf.size(); } 101 | }; 102 | 103 | 104 | /** 105 | * \class CTextA 106 | * \brief 107 | */ 108 | class CTextA 109 | { 110 | protected: 111 | std::vector _buf; 112 | bool _invalidStrLen; 113 | 114 | public: 115 | CTextA() : _invalidStrLen(false) { _buf.push_back(0); } 116 | CTextA(size_t size) : _invalidStrLen(true) { _buf.resize(size + 1, 0); } 117 | 118 | CTextA(const char* str); 119 | CTextA(const wchar_t* str); 120 | 121 | CTextA(const CTextA& txt) : _buf(txt._buf), _invalidStrLen(txt._invalidStrLen) {} 122 | 123 | ~CTextA() {} 124 | 125 | inline void AutoFit() 126 | { 127 | if (_invalidStrLen) 128 | { 129 | _buf.resize(strlen(_buf.data()) + 1, 0); 130 | _invalidStrLen = false; 131 | } 132 | } 133 | 134 | CTextA& operator=(const CTextA& txt); 135 | CTextA& operator=(const char* str); 136 | CTextA& operator=(const wchar_t* str); 137 | 138 | inline bool operator==(const CTextA& txt) const { return (_buf == txt._buf); } 139 | inline bool operator==(const char* str) const { return !strcmp(_buf.data(), str); } 140 | inline bool operator!=(const CTextA& txt) const { return !(*this == txt); } 141 | inline bool operator!=(const char* str) const { return !(*this == str); } 142 | 143 | void operator+=(const CTextA& txt); 144 | void operator+=(const char* str); 145 | void operator+=(const wchar_t* str); 146 | void operator+=(char letter); 147 | 148 | void Append(const char* data, size_t len); 149 | void Append(const wchar_t* data, size_t len); 150 | void Insert(size_t at_pos, char letter); 151 | void Insert(size_t at_pos, const char* data, size_t len); 152 | void Erase(size_t from_pos, size_t len); 153 | 154 | void Clear(); 155 | void Resize(size_t size); 156 | 157 | inline size_t Len() const { return (_invalidStrLen) ? strlen(_buf.data()) : (_buf.size() - 1); } 158 | inline bool IsEmpty() const { return (Len() == 0); } 159 | inline const std::vector& Vector() const { return _buf; } 160 | inline const char* C_str() const { return _buf.data(); } 161 | inline char* C_str() { return _buf.data(); } 162 | inline size_t Size() const { return _buf.size(); } 163 | }; 164 | 165 | 166 | /** 167 | * \class CPath 168 | * \brief 169 | */ 170 | class CPath : public CText 171 | { 172 | public: 173 | CPath() : CText() {} 174 | CPath(const CPath& path) : CText(path) {} 175 | CPath(const char* pathStr) : CText(pathStr) {} 176 | CPath(const wchar_t* pathStr) : CText(pathStr) {} 177 | CPath(size_t size) : CText(size) {} 178 | ~CPath() {} 179 | 180 | inline bool Exists() const 181 | { 182 | if (IsEmpty()) 183 | return false; 184 | DWORD dwAttrib = GetFileAttributes(C_str()); 185 | return (bool)(dwAttrib != INVALID_FILE_ATTRIBUTES); 186 | } 187 | 188 | inline bool FileExists() const 189 | { 190 | if (IsEmpty()) 191 | return false; 192 | DWORD dwAttrib = GetFileAttributes(C_str()); 193 | return (bool)(dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 194 | } 195 | 196 | void NormalizePathSlashes(); 197 | 198 | void AsFolder(); 199 | size_t StripFilename(); 200 | size_t DirUp(); 201 | 202 | const TCHAR* GetFilename() const; 203 | bool IsParentOf(const CPath& path) const; 204 | bool IsParentOf(const TCHAR* pathStr) const; 205 | bool IsSubpathOf(const CPath& path) const; 206 | bool IsSubpathOf(const TCHAR* pathStr) const; 207 | 208 | private: 209 | bool pathMatches(const TCHAR* pathStr, size_t len) const; 210 | }; 211 | 212 | 213 | namespace Tools 214 | { 215 | 216 | void ReleaseKeys(); 217 | bool BrowseForFolder(HWND hOwnerWin, CPath& path, const TCHAR* info = NULL, bool onlySubFolders = false); 218 | RECT GetWinRect(HWND hOwner, DWORD styleEx, DWORD style, int width, int height); 219 | unsigned GetFontHeight(HDC hdc, HFONT font); 220 | HFONT CreateFromSystemMessageFont(HDC hdc = NULL, unsigned fontHeight = 0); 221 | HFONT CreateFromSystemMenuFont(HDC hdc = NULL, unsigned fontHeight = 0); 222 | 223 | 224 | #ifdef DEVEL 225 | 226 | #ifdef UNICODE 227 | #define Msg(x) MsgW(x) 228 | #else 229 | #define Msg(x) MsgA(x) 230 | #endif 231 | 232 | inline void MsgW(const wchar_t* msg) 233 | { 234 | MessageBoxW(NULL, msg, L"", MB_OK); 235 | } 236 | 237 | 238 | inline void MsgA(const char* msg) 239 | { 240 | MessageBoxA(NULL, msg, "", MB_OK); 241 | } 242 | 243 | 244 | inline void MsgNum(intptr_t num, int radix = 10) 245 | { 246 | char buf[128]; 247 | _i64toa_s(num, buf, _countof(buf), radix); 248 | MessageBoxA(NULL, buf, "", MB_OK); 249 | } 250 | 251 | #endif 252 | 253 | } // namespace Tools 254 | -------------------------------------------------------------------------------- /src/Config.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags config class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "INpp.h" 30 | #include "Common.h" 31 | #include "Config.h" 32 | #include "GTags.h" 33 | 34 | 35 | namespace GTags 36 | { 37 | 38 | const TCHAR Settings::cInfo[] = 39 | _T("# Configuration file for Notepad++ ") PLUGIN_NAME _T(" plugin\n") 40 | _T("# This file is automatically generated and will be overwritten") 41 | _T(" on next ") PLUGIN_NAME _T(" config\n"); 42 | 43 | const TCHAR Settings::cKeepSearchWinOpenKey[] = _T("KeepSearchWinOpen = "); 44 | const TCHAR Settings::cTriggerAutocmplAfterKey[] = _T("TriggerAutocmplAfter = "); 45 | const TCHAR Settings::cUseDefDbKey[] = _T("UseDefaultDB = "); 46 | const TCHAR Settings::cDefDbPathKey[] = _T("DefaultDBPath = "); 47 | const TCHAR Settings::cREOptionKey[] = _T("RegExp = "); 48 | const TCHAR Settings::cICOptionKey[] = _T("IgnoreCase = "); 49 | 50 | const int Settings::cTriggerAutocmplAfterMax = 12; 51 | 52 | const TCHAR DbConfig::cInfo[] = _T("# ") PLUGIN_NAME _T(" database config\n"); 53 | 54 | const TCHAR DbConfig::cParserKey[] = _T("Parser = "); 55 | const TCHAR DbConfig::cAutoUpdateKey[] = _T("AutoUpdate = "); 56 | const TCHAR DbConfig::cUseLibDbKey[] = _T("UseLibraryDBs = "); 57 | const TCHAR DbConfig::cLibDbPathsKey[] = _T("LibraryDBPaths = "); 58 | const TCHAR DbConfig::cUsePathFilterKey[] = _T("UsePathFilters = "); 59 | const TCHAR DbConfig::cPathFiltersKey[] = _T("PathFilters = "); 60 | 61 | const TCHAR DbConfig::cDefaultParser[] = _T("default"); 62 | const TCHAR DbConfig::cCtagsParser[] = _T("ctags"); 63 | const TCHAR DbConfig::cPygmentsParser[] = _T("pygments"); 64 | 65 | const TCHAR* DbConfig::cParsers[DbConfig::PARSER_LIST_END] = { 66 | DbConfig::cDefaultParser, 67 | DbConfig::cCtagsParser, 68 | DbConfig::cPygmentsParser 69 | }; 70 | 71 | 72 | /** 73 | * \brief 74 | */ 75 | DbConfig::DbConfig() 76 | { 77 | SetDefaults(); 78 | } 79 | 80 | 81 | /** 82 | * \brief 83 | */ 84 | void DbConfig::SetDefaults() 85 | { 86 | _parserIdx = DEFAULT_PARSER; 87 | _autoUpdate = true; 88 | _useLibDb = false; 89 | _libDbPaths.clear(); 90 | _usePathFilter = false; 91 | _pathFilters.clear(); 92 | } 93 | 94 | 95 | /** 96 | * \brief 97 | */ 98 | bool DbConfig::ReadOption(TCHAR* line) 99 | { 100 | if (!_tcsncmp(line, cParserKey, _countof(cParserKey) - 1)) 101 | { 102 | const unsigned pos = _countof(cParserKey) - 1; 103 | if (!_tcsncmp(&line[pos], cCtagsParser, _countof(cCtagsParser) - 1)) 104 | _parserIdx = CTAGS_PARSER; 105 | else if (!_tcsncmp(&line[pos], cPygmentsParser, _countof(cPygmentsParser) - 1)) 106 | _parserIdx = PYGMENTS_PARSER; 107 | else 108 | _parserIdx = DEFAULT_PARSER; 109 | } 110 | else if (!_tcsncmp(line, cAutoUpdateKey, _countof(cAutoUpdateKey) - 1)) 111 | { 112 | const unsigned pos = _countof(cAutoUpdateKey) - 1; 113 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 114 | _autoUpdate = true; 115 | else 116 | _autoUpdate = false; 117 | } 118 | else if (!_tcsncmp(line, cUseLibDbKey, _countof(cUseLibDbKey) - 1)) 119 | { 120 | const unsigned pos = _countof(cUseLibDbKey) - 1; 121 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 122 | _useLibDb = true; 123 | else 124 | _useLibDb = false; 125 | } 126 | else if (!_tcsncmp(line, cLibDbPathsKey, _countof(cLibDbPathsKey) - 1)) 127 | { 128 | const unsigned pos = _countof(cLibDbPathsKey) - 1; 129 | DbPathsFromBuf(&line[pos], _T(";")); 130 | } 131 | else if (!_tcsncmp(line, cUsePathFilterKey, _countof(cUsePathFilterKey) - 1)) 132 | { 133 | const unsigned pos = _countof(cUsePathFilterKey) - 1; 134 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 135 | _usePathFilter = true; 136 | else 137 | _usePathFilter = false; 138 | } 139 | else if (!_tcsncmp(line, cPathFiltersKey, _countof(cPathFiltersKey) - 1)) 140 | { 141 | const unsigned pos = _countof(cPathFiltersKey) - 1; 142 | FiltersFromBuf(&line[pos], _T(";")); 143 | } 144 | else 145 | { 146 | return false; 147 | } 148 | 149 | return true; 150 | } 151 | 152 | 153 | /** 154 | * \brief 155 | */ 156 | bool DbConfig::Write(FILE* fp) const 157 | { 158 | bool success = false; 159 | 160 | CText libDbPaths; 161 | DbPathsToBuf(libDbPaths, _T(';')); 162 | 163 | CText pathFilters; 164 | FiltersToBuf(pathFilters, _T(';')); 165 | 166 | if (_ftprintf_s(fp, _T("%s\n"), cInfo) > 0) 167 | if (_ftprintf_s(fp, _T("%s%s\n"), cParserKey, Parser()) > 0) 168 | if (_ftprintf_s(fp, _T("%s%s\n"), cAutoUpdateKey, (_autoUpdate ? _T("yes") : _T("no"))) > 0) 169 | if (_ftprintf_s(fp, _T("%s%s\n"), cUseLibDbKey, (_useLibDb ? _T("yes") : _T("no"))) > 0) 170 | if (_ftprintf_s(fp, _T("%s%s\n"), cLibDbPathsKey, libDbPaths.C_str()) > 0) 171 | if (_ftprintf_s(fp, _T("%s%s\n"), cUsePathFilterKey, (_usePathFilter ? _T("yes") : _T("no"))) > 0) 172 | if (_ftprintf_s(fp, _T("%s%s\n"), cPathFiltersKey, pathFilters.C_str()) > 0) 173 | success = true; 174 | 175 | return success; 176 | } 177 | 178 | 179 | /** 180 | * \brief 181 | */ 182 | bool DbConfig::LoadFromFolder(const CPath& cfgFileFolder) 183 | { 184 | SetDefaults(); 185 | 186 | CPath cfgFile(cfgFileFolder); 187 | cfgFile += cPluginCfgFileName; 188 | 189 | if (!cfgFile.FileExists()) 190 | return false; 191 | 192 | FILE* fp; 193 | _tfopen_s(&fp, cfgFile.C_str(), _T("rt")); 194 | if (fp == NULL) 195 | return false; 196 | 197 | bool success = true; 198 | 199 | TCHAR line[8192]; 200 | while (_fgetts(line, _countof(line), fp)) 201 | { 202 | // Comment or empty line 203 | if (line[0] == _T('#') || line[0] == _T('\n')) 204 | continue; 205 | 206 | // Strip newline from the end of the line 207 | line[_tcslen(line) - 1] = 0; 208 | 209 | if (!ReadOption(line)) 210 | { 211 | success = false; 212 | SetDefaults(); 213 | break; 214 | } 215 | } 216 | 217 | fclose(fp); 218 | 219 | return success; 220 | } 221 | 222 | 223 | /** 224 | * \brief 225 | */ 226 | bool DbConfig::SaveToFolder(const CPath& cfgFileFolder) const 227 | { 228 | CPath cfgFile(cfgFileFolder); 229 | cfgFile += cPluginCfgFileName; 230 | 231 | FILE* fp; 232 | _tfopen_s(&fp, cfgFile.C_str(), _T("wt")); 233 | if (fp == NULL) 234 | return false; 235 | 236 | bool success = Write(fp); 237 | fclose(fp); 238 | 239 | return success; 240 | } 241 | 242 | 243 | /** 244 | * \brief 245 | */ 246 | void DbConfig::DbPathsFromBuf(TCHAR* buf, const TCHAR* separators) 247 | { 248 | TCHAR* pTmp = NULL; 249 | for (TCHAR* ptr = _tcstok_s(buf, separators, &pTmp); ptr; ptr = _tcstok_s(NULL, separators, &pTmp)) 250 | { 251 | CPath db(ptr); 252 | db.AsFolder(); 253 | if (db.Exists()) 254 | _libDbPaths.push_back(db); 255 | } 256 | } 257 | 258 | 259 | /** 260 | * \brief 261 | */ 262 | void DbConfig::DbPathsToBuf(CText& buf, TCHAR separator) const 263 | { 264 | vectorToBuf(_libDbPaths, buf, separator); 265 | } 266 | 267 | 268 | /** 269 | * \brief 270 | */ 271 | void DbConfig::FiltersFromBuf(TCHAR* buf, const TCHAR* separators) 272 | { 273 | TCHAR* pTmp = NULL; 274 | for (TCHAR* ptr = _tcstok_s(buf, separators, &pTmp); ptr; ptr = _tcstok_s(NULL, separators, &pTmp)) 275 | _pathFilters.push_back(CPath(ptr)); 276 | } 277 | 278 | 279 | /** 280 | * \brief 281 | */ 282 | void DbConfig::FiltersToBuf(CText& buf, TCHAR separator) const 283 | { 284 | vectorToBuf(_pathFilters, buf, separator); 285 | } 286 | 287 | 288 | /** 289 | * \brief 290 | */ 291 | const DbConfig& DbConfig::operator=(const DbConfig& rhs) 292 | { 293 | if (this != &rhs) 294 | { 295 | _parserIdx = rhs._parserIdx; 296 | _autoUpdate = rhs._autoUpdate; 297 | _useLibDb = rhs._useLibDb; 298 | _libDbPaths = rhs._libDbPaths; 299 | _usePathFilter = rhs._usePathFilter; 300 | _pathFilters = rhs._pathFilters; 301 | } 302 | 303 | return *this; 304 | } 305 | 306 | 307 | /** 308 | * \brief 309 | */ 310 | bool DbConfig::operator==(const DbConfig& rhs) const 311 | { 312 | if (this == &rhs) 313 | return true; 314 | 315 | return (_parserIdx == rhs._parserIdx && _autoUpdate == rhs._autoUpdate && 316 | _useLibDb == rhs._useLibDb && _libDbPaths == rhs._libDbPaths && 317 | _usePathFilter == rhs._usePathFilter && _pathFilters == rhs._pathFilters); 318 | } 319 | 320 | 321 | /** 322 | * \brief 323 | */ 324 | void DbConfig::vectorToBuf(const std::vector& vect, CText& buf, TCHAR separator) 325 | { 326 | if (!vect.size()) 327 | return; 328 | 329 | buf += vect[0]; 330 | 331 | for (unsigned i = 1; i < vect.size(); ++i) 332 | { 333 | buf += separator; 334 | buf += vect[i]; 335 | } 336 | } 337 | 338 | 339 | /** 340 | * \brief 341 | */ 342 | Settings::Settings() 343 | { 344 | SetDefaults(); 345 | } 346 | 347 | 348 | /** 349 | * \brief 350 | */ 351 | void Settings::SetDefaults() 352 | { 353 | _keepSearchWinOpen = false; 354 | _triggerAutocmplAfter = 0; 355 | _useDefDb = false; 356 | _defDbPath.Clear(); 357 | _re = false; 358 | _ic = false; 359 | 360 | _genericDbCfg.SetDefaults(); 361 | } 362 | 363 | 364 | /** 365 | * \brief 366 | */ 367 | bool Settings::Load() 368 | { 369 | SetDefaults(); 370 | 371 | CPath cfgFile; 372 | INpp::Get().GetPluginsConfDir(cfgFile); 373 | cfgFile += cPluginCfgFileName; 374 | 375 | if (!cfgFile.FileExists()) 376 | return false; 377 | 378 | FILE* fp; 379 | _tfopen_s(&fp, cfgFile.C_str(), _T("rt")); 380 | if (fp == NULL) 381 | return false; 382 | 383 | bool success = true; 384 | 385 | TCHAR line[8192]; 386 | while (_fgetts(line, _countof(line), fp)) 387 | { 388 | // Comment or empty line 389 | if (line[0] == _T('#') || line[0] == _T('\n')) 390 | continue; 391 | 392 | // Strip newline from the end of the line 393 | line[_tcslen(line) - 1] = 0; 394 | 395 | if (!_tcsncmp(line, cKeepSearchWinOpenKey, _countof(cKeepSearchWinOpenKey) - 1)) 396 | { 397 | const unsigned pos = _countof(cKeepSearchWinOpenKey) - 1; 398 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 399 | _keepSearchWinOpen = true; 400 | else 401 | _keepSearchWinOpen = false; 402 | } 403 | else if (!_tcsncmp(line, cTriggerAutocmplAfterKey, _countof(cTriggerAutocmplAfterKey) - 1)) 404 | { 405 | const unsigned pos = _countof(cTriggerAutocmplAfterKey) - 1; 406 | _triggerAutocmplAfter = _tcstol(&line[pos], nullptr, 10); 407 | if (_triggerAutocmplAfter > cTriggerAutocmplAfterMax) 408 | _triggerAutocmplAfter = cTriggerAutocmplAfterMax; 409 | } 410 | else if (!_tcsncmp(line, cUseDefDbKey, _countof(cUseDefDbKey) - 1)) 411 | { 412 | const unsigned pos = _countof(cUseDefDbKey) - 1; 413 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 414 | _useDefDb = true; 415 | else 416 | _useDefDb = false; 417 | } 418 | else if (!_tcsncmp(line, cDefDbPathKey, _countof(cDefDbPathKey) - 1)) 419 | { 420 | const unsigned pos = _countof(cDefDbPathKey) - 1; 421 | _defDbPath = &line[pos]; 422 | _defDbPath.AsFolder(); 423 | if (!_defDbPath.Exists()) 424 | _defDbPath.Clear(); 425 | } 426 | else if (!_tcsncmp(line, cREOptionKey, _countof(cREOptionKey) - 1)) 427 | { 428 | const unsigned pos = _countof(cREOptionKey) - 1; 429 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 430 | _re = true; 431 | else 432 | _re = false; 433 | } 434 | else if (!_tcsncmp(line, cICOptionKey, _countof(cICOptionKey) - 1)) 435 | { 436 | const unsigned pos = _countof(cICOptionKey) - 1; 437 | if (!_tcsncmp(&line[pos], _T("yes"), _countof(_T("yes")) - 1)) 438 | _ic = true; 439 | else 440 | _ic = false; 441 | } 442 | else if (!_genericDbCfg.ReadOption(line)) 443 | { 444 | success = false; 445 | SetDefaults(); 446 | break; 447 | } 448 | } 449 | 450 | fclose(fp); 451 | 452 | return success; 453 | } 454 | 455 | 456 | /** 457 | * \brief 458 | */ 459 | bool Settings::Save() const 460 | { 461 | CPath cfgFile; 462 | INpp::Get().GetPluginsConfDir(cfgFile); 463 | cfgFile += cPluginCfgFileName; 464 | 465 | FILE* fp; 466 | _tfopen_s(&fp, cfgFile.C_str(), _T("wt")); 467 | if (fp == NULL) 468 | return false; 469 | 470 | bool success = false; 471 | if (_ftprintf_s(fp, _T("%s\n"), cInfo) > 0) 472 | if (_ftprintf_s(fp, _T("%s%s\n"), cKeepSearchWinOpenKey, (_keepSearchWinOpen ? _T("yes") : _T("no"))) > 0) 473 | if (_ftprintf_s(fp, _T("%s%d\n"), cTriggerAutocmplAfterKey, _triggerAutocmplAfter) > 0) 474 | if (_ftprintf_s(fp, _T("%s%s\n"), cUseDefDbKey, (_useDefDb ? _T("yes") : _T("no"))) > 0) 475 | if (_ftprintf_s(fp, _T("%s%s\n"), cDefDbPathKey, _defDbPath.C_str()) > 0) 476 | if (_ftprintf_s(fp, _T("%s%s\n"), cREOptionKey, (_re ? _T("yes") : _T("no"))) > 0) 477 | if (_ftprintf_s(fp, _T("%s%s\n\n"), cICOptionKey, (_ic ? _T("yes") : _T("no"))) > 0) 478 | if (_genericDbCfg.Write(fp)) 479 | success = true; 480 | 481 | fclose(fp); 482 | 483 | if (success) 484 | _dirty = false; 485 | 486 | return success; 487 | } 488 | 489 | 490 | /** 491 | * \brief 492 | */ 493 | const Settings& Settings::operator=(const Settings& rhs) 494 | { 495 | if (this != &rhs) 496 | { 497 | _keepSearchWinOpen = rhs._keepSearchWinOpen; 498 | _triggerAutocmplAfter = rhs._triggerAutocmplAfter; 499 | _useDefDb = rhs._useDefDb; 500 | _defDbPath = rhs._defDbPath; 501 | _re = rhs._re; 502 | _ic = rhs._ic; 503 | _genericDbCfg = rhs._genericDbCfg; 504 | } 505 | 506 | return *this; 507 | } 508 | 509 | 510 | /** 511 | * \brief 512 | */ 513 | bool Settings::operator==(const Settings& rhs) const 514 | { 515 | if (this == &rhs) 516 | return true; 517 | 518 | return (_keepSearchWinOpen == rhs._keepSearchWinOpen && _triggerAutocmplAfter == rhs._triggerAutocmplAfter && 519 | _useDefDb == rhs._useDefDb && _defDbPath == rhs._defDbPath && _re == rhs._re && _ic == rhs._ic && 520 | _genericDbCfg == rhs._genericDbCfg); 521 | } 522 | 523 | } // namespace GTags 524 | -------------------------------------------------------------------------------- /src/Config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags config class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | 33 | 34 | namespace GTags 35 | { 36 | 37 | /** 38 | * \class DbConfig 39 | * \brief 40 | */ 41 | class DbConfig 42 | { 43 | public: 44 | enum 45 | { 46 | DEFAULT_PARSER = 0, 47 | CTAGS_PARSER, 48 | PYGMENTS_PARSER, 49 | PARSER_LIST_END 50 | }; 51 | 52 | DbConfig(); 53 | ~DbConfig() {} 54 | 55 | static const TCHAR* Parser(size_t idx) 56 | { 57 | return (idx < PARSER_LIST_END) ? cParsers[idx] : NULL; 58 | } 59 | 60 | const TCHAR* Parser() const { return cParsers[_parserIdx]; } 61 | 62 | void SetDefaults(); 63 | bool LoadFromFolder(const CPath& cfgFileFolder); 64 | bool SaveToFolder(const CPath& cfgFileFolder) const; 65 | 66 | void DbPathsFromBuf(TCHAR* buf, const TCHAR* separators); 67 | void DbPathsToBuf(CText& buf, TCHAR separator) const; 68 | 69 | void FiltersFromBuf(TCHAR* buf, const TCHAR* separators); 70 | void FiltersToBuf(CText& buf, TCHAR separator) const; 71 | 72 | const DbConfig& operator=(const DbConfig&); 73 | bool operator==(const DbConfig&) const; 74 | 75 | int _parserIdx; 76 | bool _autoUpdate; 77 | bool _useLibDb; 78 | std::vector _libDbPaths; 79 | bool _usePathFilter; 80 | std::vector _pathFilters; 81 | 82 | private: 83 | bool ReadOption(TCHAR* line); 84 | bool Write(FILE* fp) const; 85 | 86 | static const TCHAR cInfo[]; 87 | 88 | static const TCHAR cParserKey[]; 89 | static const TCHAR cAutoUpdateKey[]; 90 | static const TCHAR cUseLibDbKey[]; 91 | static const TCHAR cLibDbPathsKey[]; 92 | static const TCHAR cUsePathFilterKey[]; 93 | static const TCHAR cPathFiltersKey[]; 94 | 95 | static const TCHAR cDefaultParser[]; 96 | static const TCHAR cCtagsParser[]; 97 | static const TCHAR cPygmentsParser[]; 98 | 99 | static const TCHAR* cParsers[PARSER_LIST_END]; 100 | 101 | friend class Settings; 102 | 103 | static void vectorToBuf(const std::vector& vect, CText& buf, TCHAR separator); 104 | }; 105 | 106 | 107 | /** 108 | * \class Settings 109 | * \brief 110 | */ 111 | class Settings 112 | { 113 | public: 114 | static const int cTriggerAutocmplAfterMax; 115 | 116 | Settings(); 117 | ~Settings() {} 118 | 119 | void SetDefaults(); 120 | bool Load(); 121 | bool Save() const; 122 | 123 | const Settings& operator=(const Settings&); 124 | bool operator==(const Settings&) const; 125 | 126 | bool _keepSearchWinOpen; 127 | int _triggerAutocmplAfter; 128 | bool _useDefDb; 129 | CPath _defDbPath; 130 | bool _re; 131 | bool _ic; 132 | 133 | DbConfig _genericDbCfg; 134 | 135 | mutable bool _dirty = false; 136 | 137 | private: 138 | static const TCHAR cInfo[]; 139 | 140 | static const TCHAR cKeepSearchWinOpenKey[]; 141 | static const TCHAR cTriggerAutocmplAfterKey[]; 142 | static const TCHAR cUseDefDbKey[]; 143 | static const TCHAR cDefDbPathKey[]; 144 | static const TCHAR cREOptionKey[]; 145 | static const TCHAR cICOptionKey[]; 146 | }; 147 | 148 | } // namespace GTags 149 | -------------------------------------------------------------------------------- /src/DbManager.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags database manager 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include 26 | #include "DbManager.h" 27 | #include "INpp.h" 28 | #include "GTags.h" 29 | #include "Cmd.h" 30 | #include "CmdEngine.h" 31 | #include "ResultWin.h" 32 | 33 | 34 | namespace GTags 35 | { 36 | 37 | 38 | /** 39 | * \brief 40 | */ 41 | GTagsDb::GTagsDb(const CPath& dbPath, bool writeEn) : _path(dbPath), _writeLock(writeEn) 42 | { 43 | if (!_cfg.LoadFromFolder(dbPath)) 44 | _cfg = GTagsSettings._genericDbCfg; 45 | 46 | _readLocks = writeEn ? 0 : 1; 47 | } 48 | 49 | 50 | /** 51 | * \brief 52 | */ 53 | void GTagsDb::Update(const CPath& file) 54 | { 55 | CmdPtr_t cmd = std::make_shared(UPDATE_SINGLE, this->shared_from_this(), nullptr, file.C_str()); 56 | CmdEngine::Run(cmd, dbUpdateCB); 57 | } 58 | 59 | 60 | /** 61 | * \brief 62 | */ 63 | void GTagsDb::ScheduleUpdate(const CPath& file) 64 | { 65 | std::list::reverse_iterator iFile; 66 | for (iFile = _updateList.rbegin(); iFile != _updateList.rend(); ++iFile) 67 | if (*iFile == file) 68 | return; 69 | 70 | _updateList.push_back(file); 71 | } 72 | 73 | 74 | /** 75 | * \brief 76 | */ 77 | bool GTagsDb::lock(bool writeEn) 78 | { 79 | if (writeEn) 80 | { 81 | if (_writeLock || _readLocks) 82 | return false; 83 | 84 | _writeLock = true; 85 | } 86 | else 87 | { 88 | if (_writeLock) 89 | return false; 90 | 91 | ++_readLocks; 92 | } 93 | 94 | return true; 95 | } 96 | 97 | 98 | /** 99 | * \brief 100 | */ 101 | bool GTagsDb::unlock() 102 | { 103 | if (_writeLock) 104 | { 105 | _writeLock = false; 106 | } 107 | else if (_readLocks > 0) 108 | { 109 | --_readLocks; 110 | return !_readLocks; 111 | } 112 | 113 | return true; 114 | } 115 | 116 | 117 | /** 118 | * \brief 119 | */ 120 | void GTagsDb::runScheduledUpdate() 121 | { 122 | if (_updateList.empty()) 123 | return; 124 | 125 | lock(true); 126 | 127 | CPath file = *(_updateList.begin()); 128 | _updateList.erase(_updateList.begin()); 129 | 130 | Update(file); 131 | } 132 | 133 | 134 | /** 135 | * \brief 136 | */ 137 | void GTagsDb::dbUpdateCB(const CmdPtr_t& cmd) 138 | { 139 | if (cmd->Status() == RUN_ERROR) 140 | { 141 | MessageBox(INpp::Get().GetHandle(), _T("Running GTags failed"), cmd->Name(), MB_OK | MB_ICONERROR); 142 | } 143 | else if (cmd->Result()) 144 | { 145 | CText msg(cmd->Result()); 146 | MessageBox(INpp::Get().GetHandle(), msg.C_str(), cmd->Name(), MB_OK | MB_ICONEXCLAMATION); 147 | } 148 | 149 | cmd->Db()->unlock(); 150 | cmd->Db()->runScheduledUpdate(); 151 | 152 | if (cmd->Status() == OK) 153 | ResultWin::NotifyDBUpdate(cmd); 154 | } 155 | 156 | 157 | /** 158 | * \brief 159 | */ 160 | const DbHandle& DbManager::RegisterDb(const CPath& dbPath) 161 | { 162 | bool success; 163 | 164 | return lockDb(dbPath, true, &success); 165 | } 166 | 167 | 168 | /** 169 | * \brief 170 | */ 171 | bool DbManager::UnregisterDb(const DbHandle& db) 172 | { 173 | if (!db) 174 | return false; 175 | 176 | bool ret = false; 177 | 178 | for (std::list::iterator dbi = _dbList.begin(); dbi != _dbList.end(); ++dbi) 179 | { 180 | if (db == *dbi) 181 | { 182 | if (db->unlock()) 183 | { 184 | ret = deleteDb(db->_path); 185 | _dbList.erase(dbi); 186 | } 187 | 188 | break; 189 | } 190 | } 191 | 192 | return ret; 193 | } 194 | 195 | 196 | /** 197 | * \brief 198 | */ 199 | DbHandle DbManager::GetDb(const CPath& filePath, bool writeEn, bool* success) 200 | { 201 | if (!success) 202 | return NULL; 203 | 204 | *success = false; 205 | 206 | CPath dbPath(filePath); 207 | size_t len = dbPath.StripFilename(); 208 | 209 | for (; len; len = dbPath.DirUp()) 210 | if (DbExistsInFolder(dbPath)) 211 | break; 212 | 213 | if (len == 0) 214 | return NULL; 215 | 216 | return lockDb(dbPath, writeEn, success); 217 | } 218 | 219 | 220 | /** 221 | * \brief 222 | */ 223 | DbHandle DbManager::GetDbAt(const CPath& dbPath, bool writeEn, bool* success) 224 | { 225 | if (!success) 226 | return NULL; 227 | 228 | *success = false; 229 | 230 | if (!DbExistsInFolder(dbPath)) 231 | return NULL; 232 | 233 | return lockDb(dbPath, writeEn, success); 234 | } 235 | 236 | 237 | /** 238 | * \brief 239 | */ 240 | void DbManager::PutDb(const DbHandle& db) 241 | { 242 | if (!db) 243 | return; 244 | 245 | for (std::list::iterator dbi = _dbList.begin(); dbi != _dbList.end(); ++dbi) 246 | { 247 | if (db == *dbi) 248 | { 249 | if (db->unlock()) 250 | db->runScheduledUpdate(); 251 | 252 | break; 253 | } 254 | } 255 | } 256 | 257 | 258 | /** 259 | * \brief 260 | */ 261 | bool DbManager::DbExistsInFolder(const CPath& folder) 262 | { 263 | CPath db(folder); 264 | db += _T("GTAGS"); 265 | return db.FileExists(); 266 | } 267 | 268 | 269 | /** 270 | * \brief 271 | */ 272 | bool DbManager::deleteDb(CPath& dbPath) 273 | { 274 | BOOL ret = FALSE; 275 | 276 | dbPath += _T("GTAGS"); 277 | if (dbPath.FileExists()) 278 | ret = DeleteFile(dbPath.C_str()); 279 | 280 | dbPath.StripFilename(); 281 | dbPath += _T("GPATH"); 282 | if (dbPath.FileExists()) 283 | ret |= DeleteFile(dbPath.C_str()); 284 | 285 | dbPath.StripFilename(); 286 | dbPath += _T("GRTAGS"); 287 | if (dbPath.FileExists()) 288 | ret |= DeleteFile(dbPath.C_str()); 289 | 290 | dbPath.StripFilename(); 291 | dbPath += cPluginCfgFileName; 292 | if (dbPath.FileExists()) 293 | ret |= DeleteFile(dbPath.C_str()); 294 | 295 | return ret ? true : false; 296 | } 297 | 298 | 299 | /** 300 | * \brief 301 | */ 302 | const DbHandle& DbManager::lockDb(const CPath& dbPath, bool writeEn, bool* success) 303 | { 304 | for (std::list::iterator dbi = _dbList.begin(); dbi != _dbList.end(); ++dbi) 305 | { 306 | if ((*dbi)->_path == dbPath) 307 | { 308 | *success = (*dbi)->lock(writeEn); 309 | return *dbi; 310 | } 311 | } 312 | 313 | DbHandle newDb = std::make_shared(dbPath, writeEn); 314 | _dbList.push_back(newDb); 315 | 316 | *success = true; 317 | 318 | return *(_dbList.rbegin()); 319 | } 320 | 321 | } // namespace GTags 322 | -------------------------------------------------------------------------------- /src/DbManager.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags database manager 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | #include "Config.h" 33 | #include "CmdDefines.h" 34 | 35 | 36 | namespace GTags 37 | { 38 | 39 | /** 40 | * \class GTagsDb 41 | * \brief 42 | */ 43 | class GTagsDb : public std::enable_shared_from_this 44 | { 45 | public: 46 | GTagsDb(const CPath& dbPath, bool writeEn); 47 | ~GTagsDb() {} 48 | 49 | inline const CPath& GetPath() const { return _path; } 50 | 51 | inline const DbConfig& GetConfig() const { return _cfg; } 52 | inline void SetConfig(const DbConfig& cfg) { _cfg = cfg; } 53 | 54 | void Update(const CPath& file); 55 | void ScheduleUpdate(const CPath& file); 56 | 57 | inline void SaveCfg() 58 | { 59 | _cfg.SaveToFolder(_path); 60 | } 61 | 62 | private: 63 | friend class DbManager; 64 | 65 | static void dbUpdateCB(const CmdPtr_t& cmd); 66 | 67 | bool lock(bool writeEn); 68 | bool unlock(); 69 | 70 | void runScheduledUpdate(); 71 | 72 | CPath _path; 73 | DbConfig _cfg; 74 | 75 | int _readLocks; 76 | bool _writeLock; 77 | 78 | std::list _updateList; 79 | }; 80 | 81 | 82 | typedef std::shared_ptr DbHandle; 83 | 84 | 85 | /** 86 | * \class DbManager 87 | * \brief 88 | */ 89 | class DbManager 90 | { 91 | public: 92 | static DbManager& Get() 93 | { 94 | static DbManager Instance; 95 | return Instance; 96 | } 97 | 98 | const DbHandle& RegisterDb(const CPath& dbPath); 99 | bool UnregisterDb(const DbHandle& db); 100 | DbHandle GetDb(const CPath& filePath, bool writeEn, bool* success); 101 | DbHandle GetDbAt(const CPath& dbPath, bool writeEn, bool* success); 102 | void PutDb(const DbHandle& db); 103 | bool DbExistsInFolder(const CPath& folder); 104 | 105 | private: 106 | DbManager() {} 107 | DbManager(const DbManager&); 108 | ~DbManager() {} 109 | 110 | bool deleteDb(CPath& dbPath); 111 | const DbHandle& lockDb(const CPath& dbPath, bool writeEn, bool* success); 112 | 113 | std::list _dbList; 114 | }; 115 | 116 | } // namespace GTags 117 | -------------------------------------------------------------------------------- /src/DocLocation.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Stores documents locations in a stack to be visited at later time 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include "DocLocation.h" 26 | #include "Common.h" 27 | #include "INpp.h" 28 | 29 | 30 | const unsigned DocLocation::cInitialDepth = 10; 31 | 32 | 33 | /** 34 | * \brief 35 | */ 36 | void DocLocation::SetDepth(unsigned depth) 37 | { 38 | if (_locList.capacity() < depth) 39 | { 40 | _locList.reserve(depth); 41 | } 42 | else 43 | { 44 | int diff = (int)_locList.size() - depth; 45 | if (diff > 0) 46 | { 47 | _locList.erase(_locList.begin(), _locList.begin() + diff); 48 | _locList.resize(depth); 49 | _backLocIdx = (int)_locList.size() - 1; 50 | } 51 | } 52 | 53 | _maxDepth = depth; 54 | } 55 | 56 | 57 | /** 58 | * \brief 59 | */ 60 | void DocLocation::Push() 61 | { 62 | if (_backLocIdx + 1 < (int)_locList.size()) 63 | _locList.erase(_locList.begin() + _backLocIdx + 1, _locList.end()); 64 | else if (_locList.size() == _maxDepth) 65 | _locList.erase(_locList.begin()); 66 | 67 | Location loc; 68 | INpp& npp = INpp::Get(); 69 | npp.GetFilePath(loc._filePath); 70 | loc._posInFile = npp.GetPos(); 71 | 72 | if (_locList.empty() || !(loc == _locList.back())) 73 | _locList.push_back(loc); 74 | 75 | _backLocIdx = (int)_locList.size() - 1; 76 | } 77 | 78 | 79 | /** 80 | * \brief 81 | */ 82 | void DocLocation::Back() 83 | { 84 | while (_backLocIdx >= 0) 85 | { 86 | Location& loc = _locList.at(_backLocIdx--); 87 | 88 | if (loc._filePath.FileExists()) 89 | { 90 | swapView(loc); 91 | break; 92 | } 93 | } 94 | } 95 | 96 | 97 | /** 98 | * \brief 99 | */ 100 | void DocLocation::Forward() 101 | { 102 | while (_backLocIdx + 1 <= (int)_locList.size() - 1) 103 | { 104 | Location& loc = _locList.at(++_backLocIdx); 105 | 106 | if (loc._filePath.FileExists()) 107 | { 108 | swapView(loc); 109 | break; 110 | } 111 | } 112 | } 113 | 114 | 115 | /** 116 | * \brief 117 | */ 118 | void DocLocation::swapView(Location& loc) 119 | { 120 | Location newLoc; 121 | INpp& npp = INpp::Get(); 122 | 123 | npp.GetFilePath(newLoc._filePath); 124 | newLoc._posInFile = npp.GetPos(); 125 | 126 | npp.OpenFile(loc._filePath.C_str()); 127 | npp.SetView(loc._posInFile); 128 | 129 | loc = newLoc; 130 | } 131 | -------------------------------------------------------------------------------- /src/DocLocation.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Stores documents locations in a stack to be visited at later time 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2022 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | 33 | 34 | /** 35 | * \class DocLocation 36 | * \brief 37 | */ 38 | class DocLocation 39 | { 40 | public: 41 | static DocLocation& Get() 42 | { 43 | static DocLocation Instance; 44 | return Instance; 45 | } 46 | 47 | unsigned GetDepth() const { return _maxDepth; } 48 | void SetDepth(unsigned depth); 49 | void Push(); 50 | void Back(); 51 | void Forward(); 52 | 53 | private: 54 | /** 55 | * \struct Location 56 | * \brief 57 | */ 58 | struct Location 59 | { 60 | CPath _filePath; 61 | intptr_t _posInFile; 62 | 63 | inline const Location& operator=(const Location& loc) 64 | { 65 | _posInFile = loc._posInFile; 66 | _filePath = loc._filePath; 67 | return loc; 68 | } 69 | 70 | inline bool operator==(const Location& loc) const 71 | { 72 | return ((_posInFile == loc._posInFile) && (_filePath == loc._filePath)); 73 | } 74 | }; 75 | 76 | static const unsigned cInitialDepth; 77 | 78 | DocLocation() : _maxDepth(cInitialDepth), _backLocIdx(-1) {} 79 | DocLocation(const DocLocation&); 80 | ~DocLocation() {} 81 | 82 | void swapView(Location& loc); 83 | 84 | unsigned _maxDepth; 85 | int _backLocIdx; 86 | std::vector _locList; 87 | }; 88 | -------------------------------------------------------------------------------- /src/GTags.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags plugin API 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "resource.h" 32 | #include "CmdDefines.h" 33 | #include "DbManager.h" 34 | 35 | 36 | struct FuncItem; 37 | class CText; 38 | class CPath; 39 | 40 | 41 | namespace GTags 42 | { 43 | 44 | const TCHAR cPluginName[] = PLUGIN_NAME; 45 | const TCHAR cPluginCfgFileName[] = PLUGIN_NAME _T(".cfg"); 46 | const TCHAR cBinariesFolder[] = _T("bin"); 47 | 48 | enum PluginWinMessages_t 49 | { 50 | WM_RUN_CMD_CALLBACK = WM_USER, 51 | WM_OPEN_ACTIVITY_WIN, 52 | WM_CLOSE_ACTIVITY_WIN 53 | }; 54 | 55 | extern FuncItem Menu[21]; 56 | 57 | extern HINSTANCE HMod; 58 | extern CPath DllPath; 59 | 60 | extern CText UIFontName; 61 | extern unsigned UIFontSize; 62 | 63 | extern HWND MainWndH; 64 | 65 | class Settings; 66 | 67 | extern Settings GTagsSettings; 68 | 69 | extern bool NoDBFound; 70 | 71 | 72 | DbHandle getDatabase(bool writeEn = false, bool skipDialogs = false); 73 | DbHandle getDatabaseAt(const CPath& dbPath); 74 | void showResultCB(const CmdPtr_t& cmd); 75 | 76 | BOOL PluginLoad(HINSTANCE hMod); 77 | void PluginInit(); 78 | void PluginDeInit(); 79 | 80 | void OnNppReady(); 81 | void OnFileBeforeChange(const CPath& file); 82 | void OnFileChangeCancel(); 83 | void OnFileChange(const CPath& file); 84 | void OnFileRename(const CPath& file); 85 | void OnFileDelete(const CPath& file); 86 | void OnUserInput(); 87 | 88 | } // namespace GTags 89 | -------------------------------------------------------------------------------- /src/INpp.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Npp API 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include "INpp.h" 26 | #include 27 | 28 | 29 | /** 30 | * \brief 31 | */ 32 | void INpp::MultiSelectBefore(intptr_t len) const 33 | { 34 | const int selectionsCount = GetSelectionsCount(); 35 | 36 | for (int i = 0; i < selectionsCount; ++i) 37 | { 38 | const intptr_t pos = SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0); 39 | 40 | SendMessage(_hSC, SCI_SETSELECTIONNANCHOR, i, (pos < len) ? 0 : pos - len); 41 | } 42 | } 43 | 44 | 45 | /** 46 | * \brief 47 | */ 48 | void INpp::ClearSelectionMulti() const 49 | { 50 | const int selectionsCount = GetSelectionsCount(); 51 | 52 | for (int i = 0; i < selectionsCount; ++i) 53 | { 54 | const intptr_t pos = SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0); 55 | 56 | SendMessage(_hSC, SCI_SETSELECTIONNANCHOR, i, pos); 57 | } 58 | } 59 | 60 | 61 | /** 62 | * \brief 63 | */ 64 | void INpp::MultiOffsetPos(intptr_t len) const 65 | { 66 | const int selectionsCount = GetSelectionsCount(); 67 | 68 | for (int i = 0; i < selectionsCount; ++i) 69 | { 70 | const intptr_t pos = SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0); 71 | 72 | SendMessage(_hSC, SCI_SETSELECTIONNCARET, i, pos + len); 73 | } 74 | } 75 | 76 | 77 | /** 78 | * \brief 79 | */ 80 | void INpp::ClearUnmatchingWordMultiSel(const CTextA& word) const 81 | { 82 | const size_t len = word.Len(); 83 | 84 | CTextA selWord(len + 1); 85 | 86 | int i; 87 | int selectionsCount; 88 | 89 | do 90 | { 91 | selectionsCount = GetSelectionsCount(); 92 | 93 | for (i = 0; i < selectionsCount; ++i) 94 | { 95 | const intptr_t pos = SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0); 96 | const intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, pos, true); 97 | 98 | if (pos - wordStart != static_cast(len)) 99 | { 100 | SendMessage(_hSC, SCI_DROPSELECTIONN, i, 0); 101 | break; 102 | } 103 | else 104 | { 105 | struct Sci_TextRangeFull tr; 106 | tr.chrg.cpMin = pos - len; 107 | tr.chrg.cpMax = pos; 108 | tr.lpstrText = selWord.C_str(); 109 | 110 | SendMessage(_hSC, SCI_GETTEXTRANGEFULL, 0, (LPARAM)&tr); 111 | selWord.AutoFit(); 112 | 113 | if (selWord != word) 114 | { 115 | SendMessage(_hSC, SCI_DROPSELECTIONN, i, 0); 116 | break; 117 | } 118 | } 119 | } 120 | } 121 | while (i < selectionsCount); 122 | } 123 | 124 | 125 | /** 126 | * \brief 127 | */ 128 | intptr_t INpp::GetWordSize(bool partial) const 129 | { 130 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 131 | intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, currPos, true); 132 | 133 | if (partial) 134 | return currPos - wordStart; 135 | 136 | intptr_t wordEnd = SendMessage(_hSC, SCI_WORDENDPOSITION, currPos, true); 137 | 138 | return wordEnd - wordStart; 139 | } 140 | 141 | 142 | /** 143 | * \brief 144 | */ 145 | intptr_t INpp::GetWord(CTextA& word, bool partial, bool select, bool multiSel) const 146 | { 147 | const intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 148 | const intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, currPos, true); 149 | const intptr_t wordEnd = partial ? currPos : SendMessage(_hSC, SCI_WORDENDPOSITION, currPos, true); 150 | 151 | const intptr_t len = wordEnd - wordStart; 152 | 153 | if (len == 0) 154 | { 155 | word.Clear(); 156 | return len; 157 | } 158 | 159 | word.Resize(len + 1); 160 | 161 | struct Sci_TextRangeFull tr; 162 | tr.chrg.cpMin = wordStart; 163 | tr.chrg.cpMax = wordEnd; 164 | tr.lpstrText = word.C_str(); 165 | 166 | SendMessage(_hSC, SCI_GETTEXTRANGEFULL, 0, (LPARAM)&tr); 167 | word.AutoFit(); 168 | 169 | if (select) 170 | { 171 | if (multiSel) 172 | { 173 | ClearUnmatchingWordMultiSel(word); 174 | 175 | if (wordEnd != currPos) 176 | MultiOffsetPos(wordEnd - currPos); 177 | 178 | MultiSelectBefore(len); 179 | } 180 | else 181 | { 182 | SetMainSelection(wordStart, wordEnd); 183 | } 184 | } 185 | else 186 | { 187 | ClearSelectionMulti(); 188 | } 189 | 190 | return len; 191 | } 192 | 193 | 194 | /** 195 | * \brief 196 | */ 197 | void INpp::ReplaceWord(const char* replText, bool partial) const 198 | { 199 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 200 | intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, currPos, true); 201 | intptr_t wordEnd = partial ? currPos : SendMessage(_hSC, SCI_WORDENDPOSITION, currPos, true); 202 | 203 | SendMessage(_hSC, SCI_SETTARGETSTART, wordStart, 0); 204 | SendMessage(_hSC, SCI_SETTARGETEND, wordEnd, 0); 205 | 206 | SendMessage(_hSC, SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)replText); 207 | wordEnd = wordStart + strlen(replText); 208 | SendMessage(_hSC, SCI_SETSEL, wordEnd, wordEnd); 209 | } 210 | 211 | 212 | /** 213 | * \brief 214 | */ 215 | void INpp::ReplaceWordMulti(const char* replText, bool partial) const 216 | { 217 | const int selectionsCount = GetSelectionsCount(); 218 | 219 | for (int i = 0; i < selectionsCount; ++i) 220 | { 221 | const intptr_t pos = SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0); 222 | intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, pos, true); 223 | intptr_t wordEnd = partial ? pos : SendMessage(_hSC, SCI_WORDENDPOSITION, pos, true); 224 | 225 | SendMessage(_hSC, SCI_SETTARGETSTART, wordStart, 0); 226 | SendMessage(_hSC, SCI_SETTARGETEND, wordEnd, 0); 227 | 228 | SendMessage(_hSC, SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)replText); 229 | wordEnd = wordStart + strlen(replText); 230 | SendMessage(_hSC, SCI_SETSELECTIONNANCHOR, i, wordEnd); 231 | SendMessage(_hSC, SCI_SETSELECTIONNCARET, i, wordEnd); 232 | } 233 | } 234 | 235 | 236 | /** 237 | * \brief 238 | */ 239 | void INpp::EnsureCurrentLineVisible() const 240 | { 241 | intptr_t lineNum = SendMessage(_hSC, SCI_LINEFROMPOSITION, SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0), 0); 242 | SendMessage(_hSC, SCI_ENSUREVISIBLE, lineNum, 0); 243 | lineNum = SendMessage(_hSC, SCI_VISIBLEFROMDOCLINE, lineNum, 0); 244 | 245 | intptr_t linesOnScreen = SendMessage(_hSC, SCI_LINESONSCREEN, 0, 0); 246 | intptr_t firstVisibleLine = SendMessage(_hSC, SCI_GETFIRSTVISIBLELINE, 0, 0); 247 | 248 | if (lineNum < firstVisibleLine || lineNum > firstVisibleLine + linesOnScreen) 249 | { 250 | lineNum -= linesOnScreen / 2; 251 | if (lineNum < 0) 252 | lineNum = 0; 253 | SendMessage(_hSC, SCI_SETFIRSTVISIBLELINE, lineNum, 0); 254 | } 255 | } 256 | 257 | 258 | /** 259 | * \brief 260 | */ 261 | void INpp::SetView(intptr_t startPos, intptr_t endPos) const 262 | { 263 | if (endPos == 0) 264 | endPos = startPos; 265 | intptr_t lineNum = SendMessage(_hSC, SCI_LINEFROMPOSITION, startPos, 0); 266 | SendMessage(_hSC, SCI_ENSUREVISIBLE, lineNum, 0); 267 | 268 | intptr_t linesOnScreen = SendMessage(_hSC, SCI_LINESONSCREEN, 0, 0); 269 | lineNum = SendMessage(_hSC, SCI_VISIBLEFROMDOCLINE, lineNum, 0) - linesOnScreen / 2; 270 | if (lineNum < 0) 271 | lineNum = 0; 272 | 273 | SendMessage(_hSC, SCI_SETSEL, startPos, endPos); 274 | SendMessage(_hSC, SCI_SETFIRSTVISIBLELINE, lineNum, 0); 275 | } 276 | 277 | 278 | /** 279 | * \brief 280 | */ 281 | bool INpp::SearchText(const char* text, bool ignoreCase, bool wholeWord, bool regExp, 282 | intptr_t* startPos, intptr_t* endPos, bool keepView) const 283 | { 284 | if (startPos == NULL || endPos == NULL) 285 | return false; 286 | 287 | if (*startPos < 0) 288 | *startPos = 0; 289 | 290 | if (*endPos <= 0) 291 | *endPos = SendMessage(_hSC, SCI_GETLENGTH, 0, 0); 292 | 293 | int searchFlags = 0; 294 | if (!ignoreCase) 295 | searchFlags |= SCFIND_MATCHCASE; 296 | if (wholeWord) 297 | searchFlags |= SCFIND_WHOLEWORD; 298 | if (regExp) 299 | searchFlags |= (SCFIND_REGEXP | SCFIND_POSIX); 300 | 301 | SendMessage(_hSC, SCI_SETSEARCHFLAGS, (WPARAM)searchFlags, 0); 302 | SendMessage(_hSC, SCI_SETTARGETSTART, *startPos, 0); 303 | SendMessage(_hSC, SCI_SETTARGETEND, *endPos, 0); 304 | 305 | SendMessage(_hSC, SCI_SETSEL, *startPos, *endPos); 306 | bool isFound = (SendMessage(_hSC, SCI_SEARCHINTARGET, strlen(text), (LPARAM)text) >= 0); 307 | 308 | *startPos = SendMessage(_hSC, SCI_GETTARGETSTART, 0, 0); 309 | *endPos = SendMessage(_hSC, SCI_GETTARGETEND, 0, 0); 310 | 311 | if (keepView) 312 | SendMessage(_hSC, SCI_SETSEL, *startPos, *endPos); 313 | else 314 | SetView(*startPos, *endPos); 315 | 316 | return isFound; 317 | } 318 | 319 | 320 | /** 321 | * \brief 322 | */ 323 | void INpp::InsertTextAtMultiPos(const char* txt) const 324 | { 325 | const size_t txtLen = strlen(txt); 326 | 327 | const intptr_t mainPos = 328 | SendMessage(_hSC, SCI_GETSELECTIONNANCHOR, SendMessage(_hSC, SCI_GETMAINSELECTION, 0, 0), 0); 329 | 330 | std::map selSorter; 331 | 332 | const int selectionsCount = GetSelectionsCount(); 333 | 334 | for (int i = 0; i < selectionsCount; ++i) 335 | selSorter.emplace( 336 | SendMessage(_hSC, SCI_GETSELECTIONNANCHOR, i, 0), SendMessage(_hSC, SCI_GETSELECTIONNCARET, i, 0)); 337 | 338 | std::vector> selections; 339 | std::pair mainSel; 340 | 341 | size_t selOffset = 0; 342 | 343 | for (auto& sel : selSorter) 344 | { 345 | InsertTextAt(sel.second + selOffset, txt); 346 | 347 | if (sel.first != mainPos) 348 | { 349 | selections.emplace_back(sel.first + selOffset, sel.second + selOffset + txtLen); 350 | } 351 | else 352 | { 353 | mainSel.first = sel.first + selOffset; 354 | mainSel.second = sel.second + selOffset + txtLen; 355 | } 356 | 357 | selOffset += txtLen; 358 | } 359 | 360 | selections.emplace_back(mainSel); 361 | 362 | SendMessage(_hSC, SCI_SETSELECTION, selections[0].second, selections[0].first); 363 | 364 | for (size_t i = 1; i < selections.size(); ++i) 365 | SendMessage(_hSC, SCI_ADDSELECTION, selections[i].second, selections[i].first); 366 | } 367 | 368 | 369 | /** 370 | * \brief 371 | */ 372 | bool INpp::isSciWndRegistered(HWND hSciWnd) 373 | { 374 | for (std::vector::iterator iSci = _hSciWndList.begin(); iSci != _hSciWndList.end(); ++iSci) 375 | { 376 | if (*iSci == hSciWnd) 377 | return true; 378 | } 379 | 380 | return false; 381 | } 382 | -------------------------------------------------------------------------------- /src/INpp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Npp API 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "Common.h" 33 | #include "NppAPI/Notepad_plus_msgs.h" 34 | #include "NppAPI/Docking.h" 35 | #include "NppAPI/PluginInterface.h" 36 | 37 | 38 | /** 39 | * \class INpp 40 | * \brief 41 | */ 42 | class INpp 43 | { 44 | public: 45 | static inline INpp& Get() 46 | { 47 | static INpp Instance; 48 | return Instance; 49 | } 50 | 51 | inline HWND ReadSciHandle() 52 | { 53 | int currentEdit; 54 | 55 | SendMessage(_nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); 56 | 57 | _hSC = currentEdit ? _nppData._scintillaSecondHandle : _nppData._scintillaMainHandle; 58 | 59 | return _hSC; 60 | } 61 | 62 | inline void SetData(NppData nppData) 63 | { 64 | _nppData = nppData; 65 | ReadSciHandle(); 66 | } 67 | 68 | inline HWND GetHandle() const { return _nppData._nppHandle; } 69 | 70 | inline void SetSciHandle(HWND hSciWnd) 71 | { 72 | if (hSciWnd == _nppData._scintillaMainHandle || hSciWnd == _nppData._scintillaSecondHandle || 73 | isSciWndRegistered(hSciWnd)) 74 | _hSC = hSciWnd; 75 | } 76 | 77 | inline HWND GetSciHandle() const { return _hSC; } 78 | 79 | inline HWND GetSciHandle(int sciNum) const 80 | { 81 | return (sciNum ? _nppData._scintillaSecondHandle : _nppData._scintillaMainHandle); 82 | } 83 | 84 | inline void SetPluginMenuFlag(int cmdId, bool enable) const 85 | { 86 | SendMessage(_nppData._nppHandle, NPPM_SETMENUITEMCHECK, cmdId, enable); 87 | } 88 | 89 | inline int GetVersion() 90 | { 91 | return (int)::SendMessage(_nppData._nppHandle, NPPM_GETNPPVERSION, 1, 0); 92 | } 93 | 94 | inline HMENU GetPluginMenu() const 95 | { 96 | return (HMENU)SendMessage(_nppData._nppHandle, NPPM_GETMENUHANDLE, NPPPLUGINMENU, 0); 97 | } 98 | 99 | inline void RegisterWinForDarkMode(HWND hWnd) const 100 | { 101 | SendMessage(_nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, (WPARAM)NppDarkMode::dmfInit, (LPARAM)hWnd); 102 | } 103 | 104 | inline void RegisterWin(HWND hWnd) const 105 | { 106 | SendMessage(_nppData._nppHandle, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, (LPARAM)hWnd); 107 | } 108 | 109 | inline void UnregisterWin(HWND hWnd) const 110 | { 111 | SendMessage(_nppData._nppHandle, NPPM_MODELESSDIALOG, MODELESSDIALOGREMOVE, (LPARAM)hWnd); 112 | } 113 | 114 | inline void RegisterDockingWin(tTbData& data) const 115 | { 116 | SendMessage(_nppData._nppHandle, NPPM_DMMREGASDCKDLG, 0, (LPARAM)&data); 117 | } 118 | 119 | inline void ShowDockingWin(HWND hWnd) const 120 | { 121 | SendMessage(_nppData._nppHandle, NPPM_DMMSHOW, 0, (LPARAM)hWnd); 122 | } 123 | 124 | inline void HideDockingWin(HWND hWnd) const 125 | { 126 | SendMessage(_nppData._nppHandle, NPPM_DMMHIDE, 0, (LPARAM)hWnd); 127 | } 128 | 129 | inline void UpdateDockingWin(HWND hWnd) const 130 | { 131 | SendMessage(_nppData._nppHandle, NPPM_DMMUPDATEDISPINFO, 0, (LPARAM)hWnd); 132 | } 133 | 134 | inline HWND CreateSciHandle(const HWND hParentWnd) 135 | { 136 | HWND hSciWnd = (HWND)SendMessage(_nppData._nppHandle, NPPM_CREATESCINTILLAHANDLE, 0, (LPARAM)hParentWnd); 137 | 138 | if (hSciWnd) 139 | _hSciWndList.push_back(hSciWnd); 140 | 141 | return hSciWnd; 142 | } 143 | 144 | inline void GetMainDir(CPath& path) const 145 | { 146 | path.Resize(MAX_PATH); 147 | SendMessage(_nppData._nppHandle, NPPM_GETNPPDIRECTORY, (WPARAM)path.Size(), (LPARAM)path.C_str()); 148 | path += _T("\\"); 149 | } 150 | 151 | inline void GetPluginsConfDir(CPath& path) const 152 | { 153 | path.Resize(MAX_PATH); 154 | SendMessage(_nppData._nppHandle, NPPM_GETPLUGINSCONFIGDIR, (WPARAM)path.Size(), (LPARAM)path.C_str()); 155 | path += _T("\\"); 156 | } 157 | 158 | inline LRESULT getCurrentBuffId() 159 | { 160 | return SendMessage(_nppData._nppHandle, NPPM_GETCURRENTBUFFERID, 0, 0); 161 | } 162 | 163 | inline void GetFilePath(CPath& filePath) const 164 | { 165 | filePath.Resize(MAX_PATH); 166 | SendMessage(_nppData._nppHandle, NPPM_GETFULLCURRENTPATH, 0, (LPARAM)filePath.C_str()); 167 | filePath.AutoFit(); 168 | } 169 | 170 | inline void GetFilePathFromBufID(LRESULT bufId, CPath& filePath) const 171 | { 172 | filePath.Resize(MAX_PATH); 173 | SendMessage(_nppData._nppHandle, NPPM_GETFULLPATHFROMBUFFERID, bufId, (LPARAM)filePath.C_str()); 174 | filePath.AutoFit(); 175 | } 176 | 177 | inline void GetFileNamePart(CPath& fileName) const 178 | { 179 | fileName.Resize(MAX_PATH); 180 | SendMessage(_nppData._nppHandle, NPPM_GETNAMEPART, 0, (LPARAM)fileName.C_str()); 181 | fileName.AutoFit(); 182 | } 183 | 184 | inline int OpenFile(const TCHAR* filePath) 185 | { 186 | if (!SendMessage(_nppData._nppHandle, NPPM_DOOPEN, 0, (LPARAM)filePath)) 187 | return -1; 188 | 189 | UpdateWindow(_nppData._nppHandle); 190 | UpdateWindow(ReadSciHandle()); 191 | return 0; 192 | } 193 | 194 | inline void SwitchToFile(const TCHAR* filePath) const 195 | { 196 | SendMessage(_nppData._nppHandle, NPPM_SWITCHTOFILE, 0, (LPARAM)filePath); 197 | } 198 | 199 | inline bool IsLineVisible(intptr_t line) const 200 | { 201 | const intptr_t visLine = SendMessage(_hSC, SCI_VISIBLEFROMDOCLINE, line, 0); 202 | const intptr_t visEnd = visLine + SendMessage(_hSC, SCI_WRAPCOUNT, line, 0) - 1; 203 | const intptr_t firstLine = SendMessage(_hSC, SCI_GETFIRSTVISIBLELINE, 0, 0); 204 | 205 | return (firstLine <= visLine && 206 | (firstLine + SendMessage(_hSC, SCI_LINESONSCREEN, 0, 0) - 1) >= visEnd); 207 | } 208 | 209 | inline int GetCaretLineBack() const 210 | { 211 | return (int)SendMessage(_hSC, SCI_GETCARETLINEBACK, 0, 0); 212 | } 213 | 214 | inline void GetFontName(int style, char* fontName) const 215 | { 216 | SendMessage(_hSC, SCI_STYLEGETFONT, style, (LPARAM)fontName); 217 | } 218 | 219 | inline int GetFontSize(int style) const 220 | { 221 | return (int)SendMessage(_hSC, SCI_STYLEGETSIZE, style, 0); 222 | } 223 | 224 | inline int GetForegroundColor(int style) const 225 | { 226 | return (int)SendMessage(_hSC, SCI_STYLEGETFORE, style, 0); 227 | } 228 | 229 | inline int GetBackgroundColor(int style) const 230 | { 231 | return (int)SendMessage(_hSC, SCI_STYLEGETBACK, style, 0); 232 | } 233 | 234 | inline int GetTextHeight() const 235 | { 236 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 237 | currPos = SendMessage(_hSC, SCI_LINEFROMPOSITION, currPos, 0); 238 | return (int)SendMessage(_hSC, SCI_TEXTHEIGHT, currPos, 0); 239 | } 240 | 241 | inline void GetPointPos(int* x, int* y) const 242 | { 243 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 244 | *x = (int)SendMessage(_hSC, SCI_POINTXFROMPOSITION, 0, currPos) + 2; 245 | *y = (int)SendMessage(_hSC, SCI_POINTYFROMPOSITION, 0, currPos) + 2; 246 | } 247 | 248 | inline void GetPointFromPos(intptr_t pos, int* x, int* y) const 249 | { 250 | *x = (int)SendMessage(_hSC, SCI_POINTXFROMPOSITION, 0, pos) + 2; 251 | *y = (int)SendMessage(_hSC, SCI_POINTYFROMPOSITION, 0, pos) + 2; 252 | } 253 | 254 | inline intptr_t GetCurrentLine() const 255 | { 256 | return SendMessage(_hSC, SCI_LINEFROMPOSITION, SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0), 0); 257 | } 258 | 259 | inline void GoToPos(intptr_t pos) const 260 | { 261 | SendMessage(_hSC, SCI_GOTOPOS, pos, 0); 262 | } 263 | 264 | inline void GoToLine(intptr_t line) const 265 | { 266 | SendMessage(_hSC, SCI_GOTOLINE, line, 0); 267 | } 268 | 269 | inline intptr_t PositionFromLine(intptr_t line) const 270 | { 271 | return SendMessage(_hSC, SCI_POSITIONFROMLINE, line, 0); 272 | } 273 | 274 | inline intptr_t LineEndPosition(intptr_t line) const 275 | { 276 | return SendMessage(_hSC, SCI_GETLINEENDPOSITION, line, 0); 277 | } 278 | 279 | inline bool IsSelectionVertical() const 280 | { 281 | return (bool)SendMessage(_hSC, SCI_SELECTIONISRECTANGLE, 0, 0); 282 | } 283 | 284 | inline int GetSelectionsCount() const 285 | { 286 | return (int)SendMessage(_hSC, SCI_GETSELECTIONS, 0, 0); 287 | } 288 | 289 | inline bool IsMultiSelection() const 290 | { 291 | return (GetSelectionsCount() != 1); 292 | } 293 | 294 | inline intptr_t GetSelectionSize() const 295 | { 296 | return SendMessage(_hSC, SCI_GETSELTEXT, 0, 0) + 1; 297 | } 298 | 299 | inline void GetSelectionText(CTextA& sel) const 300 | { 301 | intptr_t selLen = GetSelectionSize(); 302 | 303 | sel.Resize(selLen); 304 | SendMessage(_hSC, SCI_GETSELTEXT, 0, (LPARAM)sel.C_str()); 305 | sel.AutoFit(); 306 | } 307 | 308 | inline void SetSelection(intptr_t startPos, intptr_t endPos) const 309 | { 310 | SendMessage(_hSC, SCI_SETSEL, startPos, endPos); 311 | } 312 | 313 | inline void SetMainSelection(intptr_t startPos, intptr_t endPos) const 314 | { 315 | const int sel = (int)SendMessage(_hSC, SCI_GETMAINSELECTION, 0, 0); 316 | 317 | SendMessage(_hSC, SCI_SETSELECTIONNANCHOR, sel, startPos); 318 | SendMessage(_hSC, SCI_SETSELECTIONNCARET, sel, endPos); 319 | } 320 | 321 | void MultiSelectBefore(intptr_t len) const; 322 | 323 | inline void SelectWord(bool partial = false) const 324 | { 325 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 326 | intptr_t wordStart = SendMessage(_hSC, SCI_WORDSTARTPOSITION, currPos, true); 327 | intptr_t wordEnd = partial ? currPos : SendMessage(_hSC, SCI_WORDENDPOSITION, currPos, true); 328 | 329 | SendMessage(_hSC, SCI_SETSEL, wordStart, wordEnd); 330 | } 331 | 332 | inline bool IsRangeWord(intptr_t startPos, intptr_t endPos) const 333 | { 334 | return SendMessage(_hSC, SCI_ISRANGEWORD, startPos, endPos); 335 | } 336 | 337 | inline void ClearSelection() const 338 | { 339 | intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 340 | SendMessage(_hSC, SCI_SETSEL, currPos, currPos); 341 | } 342 | 343 | void ClearSelectionMulti() const; 344 | void MultiOffsetPos(intptr_t len) const; 345 | void ClearUnmatchingWordMultiSel(const CTextA& word) const; 346 | 347 | inline intptr_t GetPos() const 348 | { 349 | return SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0); 350 | } 351 | 352 | void EnsureCurrentLineVisible() const; 353 | void SetView(intptr_t startPos, intptr_t endPos = 0) const; 354 | 355 | intptr_t GetWordSize(bool partial = false) const; 356 | intptr_t GetWord(CTextA& word, bool partial = false, bool select = false, bool multiSel = false) const; 357 | void ReplaceWord(const char* replText, bool partial = false) const; 358 | void ReplaceWordMulti(const char* replText, bool partial = false) const; 359 | bool SearchText(const char* text, bool ignoreCase, bool wholeWord, bool regExp, 360 | intptr_t* startPos = NULL, intptr_t* endPos = NULL, bool keepView = false) const; 361 | 362 | inline bool IsPreviousCharWordEnd() 363 | { 364 | const intptr_t currPos = SendMessage(_hSC, SCI_GETCURRENTPOS, 0, 0) - 1; 365 | 366 | return (currPos > 0) && (SendMessage(_hSC, SCI_WORDENDPOSITION, currPos, true) == currPos); 367 | } 368 | 369 | inline void Backspace() const 370 | { 371 | SendMessage(_hSC, SCI_DELETEBACK, 0, 0); 372 | } 373 | 374 | inline char GetChar(intptr_t pos) const 375 | { 376 | return (char)SendMessage(_hSC, SCI_GETCHARAT, pos, 0); 377 | } 378 | 379 | inline void AddText(const char* txt, size_t len) const 380 | { 381 | SendMessage(_hSC, SCI_ADDTEXT, len, (LPARAM)txt); 382 | } 383 | 384 | void InsertTextAt(intptr_t pos, const char* txt) const 385 | { 386 | SendMessage(_hSC, SCI_INSERTTEXT, pos, (LPARAM)txt); 387 | } 388 | 389 | void InsertTextAtMultiPos(const char* txt) const; 390 | 391 | inline void BeginUndoAction() const 392 | { 393 | SendMessage(_hSC, SCI_BEGINUNDOACTION, 0, 0); 394 | } 395 | 396 | inline void EndUndoAction() const 397 | { 398 | SendMessage(_hSC, SCI_ENDUNDOACTION, 0, 0); 399 | } 400 | 401 | private: 402 | INpp() : _hSC(NULL) {} 403 | INpp(const INpp&); 404 | ~INpp() {} 405 | 406 | bool isSciWndRegistered(HWND hSciWnd); 407 | 408 | NppData _nppData; 409 | HWND _hSC; 410 | std::vector _hSciWndList; 411 | }; 412 | -------------------------------------------------------------------------------- /src/LineParser.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Line parser (splitter) class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2022 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include "LineParser.h" 26 | #include "StrUniquenessChecker.h" 27 | 28 | 29 | namespace GTags 30 | { 31 | 32 | /** 33 | * \brief 34 | */ 35 | intptr_t LineParser::Parse(const CmdPtr_t& cmd) 36 | { 37 | intptr_t result = 0; 38 | 39 | const bool filterReoccurring = cmd->Db()->GetConfig()._useLibDb; 40 | 41 | StrUniquenessChecker strChecker; 42 | 43 | _lines.clear(); 44 | _buf = cmd->Result(); 45 | 46 | TCHAR* pTmp = NULL; 47 | for (TCHAR* pToken = _tcstok_s(_buf.C_str(), _T("\n\r"), &pTmp); pToken; 48 | pToken = _tcstok_s(NULL, _T("\n\r"), &pTmp)) 49 | { 50 | if (cmd->Id() == FIND_FILE || cmd->Id() == AUTOCOMPLETE_FILE) 51 | ++pToken; 52 | 53 | if ((!filterReoccurring) || strChecker.IsUnique(pToken)) 54 | { 55 | _lines.push_back(pToken); 56 | ++result; 57 | } 58 | } 59 | 60 | return result; 61 | } 62 | 63 | } // namespace GTags 64 | -------------------------------------------------------------------------------- /src/LineParser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Line parser (splitter) class 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2022 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "Common.h" 34 | #include "Cmd.h" 35 | 36 | 37 | namespace GTags 38 | { 39 | 40 | /** 41 | * \class LineParser 42 | * \brief 43 | */ 44 | class LineParser : public ResultParser 45 | { 46 | public: 47 | LineParser() {} 48 | virtual ~LineParser() {} 49 | 50 | virtual intptr_t Parse(const CmdPtr_t&); 51 | 52 | private: 53 | CText _buf; 54 | }; 55 | 56 | } // namespace GTags 57 | -------------------------------------------------------------------------------- /src/NppAPI/Docking.h: -------------------------------------------------------------------------------- 1 | // This file is part of Notepad++ project 2 | // Copyright (C)2022 Don HO 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | 18 | #pragma once 19 | 20 | #include 21 | 22 | // ATTENTION : It's a part of interface header, so don't include the others header here 23 | 24 | // styles for containers 25 | #define CAPTION_TOP TRUE 26 | #define CAPTION_BOTTOM FALSE 27 | 28 | // defines for docking manager 29 | #define CONT_LEFT 0 30 | #define CONT_RIGHT 1 31 | #define CONT_TOP 2 32 | #define CONT_BOTTOM 3 33 | #define DOCKCONT_MAX 4 34 | 35 | // mask params for plugins of internal dialogs 36 | #define DWS_ICONTAB 0x00000001 // Icon for tabs are available 37 | #define DWS_ICONBAR 0x00000002 // Icon for icon bar are available (currently not supported) 38 | #define DWS_ADDINFO 0x00000004 // Additional information are in use 39 | #define DWS_PARAMSALL (DWS_ICONTAB|DWS_ICONBAR|DWS_ADDINFO) 40 | 41 | // default docking values for first call of plugin 42 | #define DWS_DF_CONT_LEFT (CONT_LEFT << 28) // default docking on left 43 | #define DWS_DF_CONT_RIGHT (CONT_RIGHT << 28) // default docking on right 44 | #define DWS_DF_CONT_TOP (CONT_TOP << 28) // default docking on top 45 | #define DWS_DF_CONT_BOTTOM (CONT_BOTTOM << 28) // default docking on bottom 46 | #define DWS_DF_FLOATING 0x80000000 // default state is floating 47 | 48 | 49 | struct tTbData { 50 | HWND hClient = nullptr; // client Window Handle 51 | const TCHAR* pszName = nullptr; // name of plugin (shown in window) 52 | int dlgID = 0; // a funcItem provides the function pointer to start a dialog. Please parse here these ID 53 | 54 | // user modifications 55 | UINT uMask = 0; // mask params: look to above defines 56 | HICON hIconTab = nullptr; // icon for tabs 57 | const TCHAR* pszAddInfo = nullptr; // for plugin to display additional informations 58 | 59 | // internal data, do not use !!! 60 | RECT rcFloat = {}; // floating position 61 | int iPrevCont = 0; // stores the privious container (toggling between float and dock) 62 | const TCHAR* pszModuleName = nullptr; // it's the plugin file name. It's used to identify the plugin 63 | }; 64 | 65 | 66 | struct tDockMgr { 67 | HWND hWnd = nullptr; // the docking manager wnd 68 | RECT rcRegion[DOCKCONT_MAX] = {{}}; // position of docked dialogs 69 | }; 70 | 71 | 72 | #define HIT_TEST_THICKNESS 20 73 | #define SPLITTER_WIDTH 4 74 | 75 | -------------------------------------------------------------------------------- /src/NppAPI/PluginInterface.h: -------------------------------------------------------------------------------- 1 | // This file is part of Notepad++ project 2 | // Copyright (C)2024 Don HO 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | 18 | 19 | // For more comprehensive information on plugin communication, please refer to the following resource: 20 | // https://npp-user-manual.org/docs/plugin-communication/ 21 | 22 | #pragma once 23 | 24 | #include "Scintilla.h" 25 | #include "Notepad_plus_msgs.h" 26 | 27 | 28 | typedef const TCHAR * (__cdecl * PFUNCGETNAME)(); 29 | 30 | struct NppData 31 | { 32 | HWND _nppHandle = nullptr; 33 | HWND _scintillaMainHandle = nullptr; 34 | HWND _scintillaSecondHandle = nullptr; 35 | }; 36 | 37 | typedef void (__cdecl * PFUNCSETINFO)(NppData); 38 | typedef void (__cdecl * PFUNCPLUGINCMD)(); 39 | typedef void (__cdecl * PBENOTIFIED)(SCNotification *); 40 | typedef LRESULT (__cdecl * PMESSAGEPROC)(UINT Message, WPARAM wParam, LPARAM lParam); 41 | 42 | 43 | struct ShortcutKey 44 | { 45 | bool _isCtrl = false; 46 | bool _isAlt = false; 47 | bool _isShift = false; 48 | UCHAR _key = 0; 49 | }; 50 | 51 | const int menuItemSize = 64; 52 | 53 | struct FuncItem 54 | { 55 | FuncItem(const TCHAR* itemName = NULL, PFUNCPLUGINCMD pFunc = NULL, 56 | bool init2Check = false, ShortcutKey* pShKey = NULL) : 57 | _pFunc(pFunc), _init2Check(init2Check), _pShKey(pShKey) 58 | { 59 | if (itemName != NULL) 60 | _tcscpy_s(_itemName, menuItemSize, itemName); 61 | else 62 | _itemName[0] = 0; 63 | } 64 | 65 | TCHAR _itemName[menuItemSize] = { '\0' }; 66 | PFUNCPLUGINCMD _pFunc = nullptr; 67 | int _cmdID = 0; 68 | bool _init2Check = false; 69 | ShortcutKey *_pShKey = nullptr; 70 | }; 71 | 72 | typedef FuncItem * (__cdecl * PFUNCGETFUNCSARRAY)(int *); 73 | 74 | // You should implement (or define an empty function body) those functions which are called by Notepad++ plugin manager 75 | extern "C" __declspec(dllexport) void setInfo(NppData); 76 | extern "C" __declspec(dllexport) const TCHAR * getName(); 77 | extern "C" __declspec(dllexport) FuncItem * getFuncsArray(int *); 78 | extern "C" __declspec(dllexport) void beNotified(SCNotification *); 79 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam); 80 | 81 | // This API return always true now, since Notepad++ isn't compiled in ANSI mode anymore 82 | extern "C" __declspec(dllexport) BOOL isUnicode(); 83 | 84 | -------------------------------------------------------------------------------- /src/NppAPI/Sci_Position.h: -------------------------------------------------------------------------------- 1 | // Scintilla source code edit control 2 | /** @file Sci_Position.h 3 | ** Define the Sci_Position type used in Scintilla's external interfaces. 4 | ** These need to be available to clients written in C so are not in a C++ namespace. 5 | **/ 6 | // Copyright 2015 by Neil Hodgson 7 | // The License.txt file describes the conditions under which this software may be distributed. 8 | 9 | #ifndef SCI_POSITION_H 10 | #define SCI_POSITION_H 11 | 12 | #include 13 | 14 | // Basic signed type used throughout interface 15 | typedef ptrdiff_t Sci_Position; 16 | 17 | // Unsigned variant used for ILexer::Lex and ILexer::Fold 18 | typedef size_t Sci_PositionU; 19 | 20 | // For Sci_CharacterRange which is defined as long to be compatible with Win32 CHARRANGE 21 | typedef intptr_t Sci_PositionCR; 22 | 23 | #ifdef _WIN32 24 | #define SCI_METHOD __stdcall 25 | #else 26 | #define SCI_METHOD 27 | #endif 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/NppAPI/dockingResource.h: -------------------------------------------------------------------------------- 1 | // This file is part of Notepad++ project 2 | // Copyright (C)2006 Jens Lorenz 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | 18 | #pragma once 19 | 20 | #define DM_NOFOCUSWHILECLICKINGCAPTION TEXT("NOFOCUSWHILECLICKINGCAPTION") 21 | 22 | #define IDD_PLUGIN_DLG 103 23 | #define IDC_EDIT1 1000 24 | 25 | 26 | #define IDB_CLOSE_DOWN 137 27 | #define IDB_CLOSE_UP 138 28 | #define IDD_CONTAINER_DLG 139 29 | 30 | #define IDC_TAB_CONT 1027 31 | #define IDC_CLIENT_TAB 1028 32 | #define IDC_BTN_CAPTION 1050 33 | 34 | #define DMM_MSG 0x5000 35 | #define DMM_CLOSE (DMM_MSG + 1) 36 | #define DMM_DOCK (DMM_MSG + 2) 37 | #define DMM_FLOAT (DMM_MSG + 3) 38 | #define DMM_DOCKALL (DMM_MSG + 4) 39 | #define DMM_FLOATALL (DMM_MSG + 5) 40 | #define DMM_MOVE (DMM_MSG + 6) 41 | #define DMM_UPDATEDISPINFO (DMM_MSG + 7) 42 | #define DMM_GETIMAGELIST (DMM_MSG + 8) 43 | #define DMM_GETICONPOS (DMM_MSG + 9) 44 | #define DMM_DROPDATA (DMM_MSG + 10) 45 | #define DMM_MOVE_SPLITTER (DMM_MSG + 11) 46 | #define DMM_CANCEL_MOVE (DMM_MSG + 12) 47 | #define DMM_LBUTTONUP (DMM_MSG + 13) 48 | 49 | #define DMN_FIRST 1050 50 | #define DMN_CLOSE (DMN_FIRST + 1) 51 | //nmhdr.code = DWORD(DMN_CLOSE, 0)); 52 | //nmhdr.hwndFrom = hwndNpp; 53 | //nmhdr.idFrom = ctrlIdNpp; 54 | 55 | #define DMN_DOCK (DMN_FIRST + 2) 56 | #define DMN_FLOAT (DMN_FIRST + 3) 57 | //nmhdr.code = DWORD(DMN_XXX, int newContainer); 58 | //nmhdr.hwndFrom = hwndNpp; 59 | //nmhdr.idFrom = ctrlIdNpp; 60 | 61 | #define DMN_SWITCHIN (DMN_FIRST + 4) 62 | #define DMN_SWITCHOFF (DMN_FIRST + 5) 63 | #define DMN_FLOATDROPPED (DMN_FIRST + 6) 64 | //nmhdr.code = DWORD(DMN_XXX, 0); 65 | //nmhdr.hwndFrom = DockingCont::_hself; 66 | //nmhdr.idFrom = 0; 67 | 68 | -------------------------------------------------------------------------------- /src/PluginInterface.cpp: -------------------------------------------------------------------------------- 1 | // this file is part of notepad++ 2 | // Copyright (C)2003 Don HO 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either 7 | // version 2 of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | 19 | #include 20 | #include 21 | #include "NppAPI/PluginInterface.h" 22 | #include "NppAPI/Notepad_plus_msgs.h" 23 | #include "NppAPI/menuCmdID.h" 24 | #include "Common.h" 25 | #include "INpp.h" 26 | #include "ResultWin.h" 27 | #include "GTags.h" 28 | 29 | 30 | BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reasonForCall, LPVOID ) 31 | { 32 | switch (reasonForCall) 33 | { 34 | case DLL_PROCESS_ATTACH: 35 | return GTags::PluginLoad(hModule); 36 | 37 | case DLL_PROCESS_DETACH: 38 | GTags::PluginDeInit(); 39 | break; 40 | 41 | case DLL_THREAD_ATTACH: 42 | break; 43 | 44 | case DLL_THREAD_DETACH: 45 | break; 46 | } 47 | 48 | return TRUE; 49 | } 50 | 51 | 52 | extern "C" __declspec(dllexport) void setInfo(NppData nppData) 53 | { 54 | INpp& npp = INpp::Get(); 55 | npp.SetData(nppData); 56 | 57 | GTags::PluginInit(); 58 | } 59 | 60 | 61 | extern "C" __declspec(dllexport) const TCHAR* getName() 62 | { 63 | return GTags::cPluginName; 64 | } 65 | 66 | 67 | extern "C" __declspec(dllexport) FuncItem* getFuncsArray(int* nbF) 68 | { 69 | *nbF = _countof(GTags::Menu); 70 | return GTags::Menu; 71 | } 72 | 73 | 74 | extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode) 75 | { 76 | switch (notifyCode->nmhdr.code) 77 | { 78 | case SCN_CHARADDED: 79 | { 80 | if (GTags::GTagsSettings._triggerAutocmplAfter && 81 | (notifyCode->characterSource == SC_CHARACTERSOURCE_DIRECT_INPUT) && !GTags::NoDBFound) 82 | GTags::OnUserInput(); 83 | } 84 | break; 85 | 86 | case NPPN_BUFFERACTIVATED: 87 | GTags::NoDBFound = false; 88 | break; 89 | 90 | case NPPN_FILESAVED: 91 | { 92 | CPath file; 93 | INpp::Get().GetFilePathFromBufID(notifyCode->nmhdr.idFrom, file); 94 | GTags::OnFileChange(file); 95 | } 96 | break; 97 | 98 | case NPPN_FILEBEFORERENAME: 99 | case NPPN_FILEBEFOREDELETE: 100 | { 101 | CPath file; 102 | INpp::Get().GetFilePathFromBufID(notifyCode->nmhdr.idFrom, file); 103 | GTags::OnFileBeforeChange(file); 104 | } 105 | break; 106 | 107 | case NPPN_FILERENAMECANCEL: 108 | case NPPN_FILEDELETEFAILED: 109 | GTags::OnFileChangeCancel(); 110 | break; 111 | 112 | case NPPN_FILERENAMED: 113 | { 114 | CPath file; 115 | INpp::Get().GetFilePathFromBufID(notifyCode->nmhdr.idFrom, file); 116 | GTags::OnFileRename(file); 117 | } 118 | break; 119 | 120 | case NPPN_FILEDELETED: 121 | { 122 | CPath file; 123 | INpp::Get().GetFilePathFromBufID(notifyCode->nmhdr.idFrom, file); 124 | GTags::OnFileDelete(file); 125 | } 126 | break; 127 | 128 | case NPPN_WORDSTYLESUPDATED: 129 | { 130 | INpp& npp = INpp::Get(); 131 | char font[32]; 132 | 133 | npp.GetFontName(STYLE_DEFAULT, font); 134 | GTags::UIFontName = font; 135 | GTags::UIFontSize = (unsigned)npp.GetFontSize(STYLE_DEFAULT); 136 | GTags::ResultWin::ApplyStyle(); 137 | } 138 | break; 139 | 140 | case NPPN_READY: 141 | GTags::OnNppReady(); 142 | break; 143 | 144 | case NPPN_SHUTDOWN: 145 | GTags::PluginDeInit(); 146 | break; 147 | } 148 | } 149 | 150 | 151 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT , WPARAM , LPARAM ) 152 | { 153 | return TRUE; 154 | } 155 | 156 | 157 | extern "C" __declspec(dllexport) BOOL isUnicode() 158 | { 159 | #ifdef UNICODE 160 | return TRUE; 161 | #else 162 | return FALSE; 163 | #endif 164 | } 165 | -------------------------------------------------------------------------------- /src/ReadPipe.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Class that reads piped process output 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2015 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #include "ReadPipe.h" 26 | #include 27 | 28 | 29 | const unsigned ReadPipe::cChunkSize = 4096; 30 | 31 | 32 | /** 33 | * \brief 34 | */ 35 | ReadPipe::ReadPipe() : _hIn(NULL), _hOut(NULL), _hThread(NULL) 36 | { 37 | SECURITY_ATTRIBUTES attr = {0}; 38 | attr.nLength = sizeof(attr); 39 | attr.bInheritHandle = TRUE; 40 | 41 | _ready = CreatePipe(&_hOut, &_hIn, &attr, 0); 42 | if (_ready) 43 | _ready = SetHandleInformation(_hOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); 44 | } 45 | 46 | 47 | /** 48 | * \brief 49 | */ 50 | ReadPipe::~ReadPipe() 51 | { 52 | if (_hThread) 53 | { 54 | Wait(INFINITE); 55 | } 56 | else 57 | { 58 | if (_hIn) 59 | CloseHandle(_hIn); 60 | if (_hOut) 61 | CloseHandle(_hOut); 62 | } 63 | } 64 | 65 | 66 | /** 67 | * \brief 68 | */ 69 | bool ReadPipe::Open() 70 | { 71 | if (!_ready || !_hOut) 72 | return false; 73 | if (_hThread) 74 | return true; 75 | 76 | CloseHandle(_hIn); 77 | _hIn = NULL; 78 | _hThread = (HANDLE)_beginthreadex(NULL, 0, threadFunc, this, 0, NULL); 79 | if (_hThread) 80 | return true; 81 | 82 | // on error 83 | CloseHandle(_hOut); 84 | _hOut = NULL; 85 | return false; 86 | } 87 | 88 | 89 | /** 90 | * \brief 91 | */ 92 | DWORD ReadPipe::Wait(DWORD time_ms) 93 | { 94 | if (!_hThread) 95 | return WAIT_OBJECT_0; 96 | 97 | DWORD r = WaitForSingleObject(_hThread, time_ms); 98 | if (r != WAIT_TIMEOUT) 99 | { 100 | CloseHandle(_hOut); 101 | _hOut = NULL; 102 | CloseHandle(_hThread); 103 | _hThread = NULL; 104 | } 105 | 106 | return r; 107 | } 108 | 109 | 110 | /** 111 | * \brief 112 | */ 113 | std::vector& ReadPipe::GetOutput() 114 | { 115 | if (_hThread) 116 | Wait(INFINITE); 117 | 118 | return _output; 119 | } 120 | 121 | 122 | /** 123 | * \brief 124 | */ 125 | unsigned __stdcall ReadPipe::threadFunc(void* data) 126 | { 127 | return static_cast(data)->thread(); 128 | } 129 | 130 | 131 | /** 132 | * \brief 133 | */ 134 | unsigned ReadPipe::thread() 135 | { 136 | DWORD bytesRead = 0; 137 | unsigned totalBytesRead = 0; 138 | unsigned chunkRemainingSize = 0; 139 | 140 | for (;;) 141 | { 142 | if (!chunkRemainingSize) 143 | { 144 | _output.resize(totalBytesRead + cChunkSize); 145 | chunkRemainingSize = cChunkSize; 146 | } 147 | 148 | if (!ReadFile(_hOut, _output.data() + totalBytesRead, chunkRemainingSize, &bytesRead, NULL)) 149 | break; 150 | 151 | chunkRemainingSize -= bytesRead; 152 | totalBytesRead += bytesRead; 153 | } 154 | 155 | _output.resize(totalBytesRead); 156 | if (totalBytesRead) 157 | _output.push_back(0); 158 | 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /src/ReadPipe.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Class that reads piped process output 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2015 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | 31 | 32 | /** 33 | * \class ReadPipe 34 | * \brief 35 | */ 36 | class ReadPipe 37 | { 38 | public: 39 | ReadPipe(); 40 | ~ReadPipe(); 41 | 42 | HANDLE GetInputHandle() { return _hIn; } 43 | bool Open(); 44 | DWORD Wait(DWORD time_ms); 45 | std::vector& GetOutput(); 46 | 47 | private: 48 | static const unsigned cChunkSize; 49 | 50 | static unsigned __stdcall threadFunc(void* data); 51 | 52 | ReadPipe(const ReadPipe&); 53 | const ReadPipe& operator=(const ReadPipe&); 54 | 55 | unsigned thread(); 56 | 57 | BOOL _ready; 58 | HANDLE _hIn; 59 | HANDLE _hOut; 60 | HANDLE _hThread; 61 | std::vector _output; 62 | }; 63 | -------------------------------------------------------------------------------- /src/ResultWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags result Scintilla view window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "NppAPI/Scintilla.h" 36 | #include "Common.h" 37 | #include "Cmd.h" 38 | 39 | 40 | namespace GTags 41 | { 42 | 43 | /** 44 | * \class ResultWin 45 | * \brief 46 | */ 47 | class ResultWin 48 | { 49 | public: 50 | /** 51 | * \class TabParser 52 | * \brief 53 | */ 54 | class TabParser : public ResultParser 55 | { 56 | public: 57 | TabParser() : _filesCount(0), _hits(0), _headerStatusLen(0) {} 58 | virtual ~TabParser() {} 59 | 60 | virtual intptr_t Parse(const CmdPtr_t&); 61 | 62 | inline intptr_t getFilesCount() const { return _filesCount; } 63 | inline intptr_t getHitsCount() const { return _hits ? _hits : _filesCount; } 64 | inline int getHeaderStatusLen() const { return _headerStatusLen; } 65 | 66 | inline void addResultFile(const char* pFile, size_t len, intptr_t line) 67 | { 68 | _fileResults.emplace(std::string(pFile, len), line); 69 | } 70 | 71 | inline bool isFileInResults(const std::string& file) const 72 | { 73 | return (_fileResults.find(file) != _fileResults.end()); 74 | } 75 | 76 | inline const std::string& getFirstFileResult() const { return _fileResults.begin()->first; } 77 | inline const std::unordered_map& getFileResults() const { return _fileResults; } 78 | 79 | private: 80 | static bool filterEntry(const DbConfig& cfg, const char* pEntry, size_t len); 81 | 82 | intptr_t parseCmd(const CmdPtr_t&); 83 | intptr_t parseFindFile(const CmdPtr_t&); 84 | 85 | intptr_t _filesCount; 86 | intptr_t _hits; 87 | int _headerStatusLen; 88 | 89 | std::unordered_map _fileResults; 90 | }; 91 | 92 | 93 | static HWND Register(); 94 | static void Unregister(); 95 | 96 | static void Show() 97 | { 98 | if (RW) 99 | RW->show(); 100 | } 101 | 102 | static void Show(const CmdPtr_t& cmd) 103 | { 104 | if (RW) 105 | RW->show(cmd); 106 | } 107 | 108 | static void Close(const CmdPtr_t& cmd) 109 | { 110 | if (RW) 111 | RW->close(cmd); 112 | } 113 | 114 | static void ApplyStyle() 115 | { 116 | if (RW) 117 | RW->applyStyle(); 118 | } 119 | 120 | static void NotifyDBUpdate(const CmdPtr_t& cmd) 121 | { 122 | if (RW) 123 | RW->notifyDBUpdate(cmd); 124 | } 125 | 126 | static HWND GetSciHandleIfFocused() 127 | { 128 | if (RW && GetFocus() == ResultWin::_hSci) 129 | return ResultWin::_hSci; 130 | 131 | return NULL; 132 | } 133 | 134 | static CPath GetDbPath() 135 | { 136 | if (RW && RW->_activeTab) 137 | return CPath(RW->_activeTab->_projectPath.C_str()); 138 | 139 | return CPath(); 140 | } 141 | 142 | static bool IsFocused(HWND hWnd = NULL) 143 | { 144 | if (hWnd == NULL) 145 | hWnd = GetFocus(); 146 | 147 | return (RW && (RW->_hWnd == hWnd || IsChild(RW->_hWnd, hWnd))); 148 | }; 149 | 150 | static bool Activate(); 151 | 152 | ResultWin() : _hWnd(NULL), _hKeyHook(NULL), _activeTab(NULL), 153 | _hSearch(NULL), _hSearchFont(NULL), _hBtnFont(NULL), 154 | _lastRE(false), _lastIC(false), _lastWW(true) {} 155 | ~ResultWin(); 156 | 157 | private: 158 | /** 159 | * \struct Tab 160 | * \brief 161 | */ 162 | struct Tab 163 | { 164 | Tab(const CmdPtr_t& cmd); 165 | ~Tab() {} 166 | Tab& operator=(const Tab&) = delete; 167 | 168 | inline bool operator==(const Tab& tab) const 169 | { 170 | return (_cmdId == tab._cmdId && _projectPath == tab._projectPath && _search == tab._search && 171 | _ignoreCase == tab._ignoreCase && _regExp == tab._regExp); 172 | } 173 | 174 | const CmdId_t _cmdId; 175 | const bool _regExp; 176 | const bool _ignoreCase; 177 | CTextA _projectPath; 178 | CTextA _search; 179 | intptr_t _currentLine; 180 | intptr_t _firstVisibleLine; 181 | ParserPtr_t _parser; 182 | 183 | bool _dirty; 184 | 185 | inline void SetFolded(intptr_t lineNum); 186 | inline void SetAllFolded(); 187 | inline void ClearFolded(intptr_t lineNum); 188 | inline bool IsFolded(intptr_t lineNum); 189 | 190 | void RestoreView(const Tab& oldTab); 191 | 192 | private: 193 | std::unordered_set _expandedLines; 194 | }; 195 | 196 | 197 | static const COLORREF cBlack = RGB(0,0,0); 198 | static const COLORREF cWhite = RGB(255,255,255); 199 | 200 | static const TCHAR cClassName[]; 201 | static const TCHAR cSearchClassName[]; 202 | 203 | static const int cSearchBkgndColor; 204 | static const unsigned cSearchFontSize; 205 | static const int cSearchWidth; 206 | 207 | static LRESULT CALLBACK keyHookProc(int code, WPARAM wParam, LPARAM lParam); 208 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 209 | static LRESULT APIENTRY searchWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 210 | 211 | ResultWin(const ResultWin&); 212 | 213 | void show(); 214 | void show(const CmdPtr_t& cmd); 215 | void close(const CmdPtr_t& cmd); 216 | void reRunCmd(); 217 | void applyStyle(); 218 | void notifyDBUpdate(const CmdPtr_t& cmd); 219 | 220 | inline LRESULT sendSci(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0) 221 | { 222 | return _sciFunc(_sciPtr, static_cast(Msg), 223 | static_cast(wParam), static_cast(lParam)); 224 | } 225 | 226 | void setStyle(int style, COLORREF fore = cBlack, COLORREF back = cWhite, bool bold = false, bool italic = false, 227 | int size = 0, const char *font = NULL); 228 | 229 | void configScintilla(); 230 | HWND composeWindow(); 231 | void createSearchWindow(); 232 | void onSearchWindowCreate(HWND hWnd); 233 | void showWindow(HWND hFocus = NULL); 234 | void hideWindow(); 235 | 236 | void hookKeyboard() 237 | { 238 | _hKeyHook = SetWindowsHookEx(WH_KEYBOARD, keyHookProc, NULL, GetCurrentThreadId()); 239 | } 240 | 241 | Tab* getTab(int i = -1); 242 | void loadTab(Tab* tab, bool firstTimeLoad = false); 243 | bool visitSingleResult(Tab* tab); 244 | bool openItem(intptr_t lineNum, unsigned matchNum = 1); 245 | 246 | bool findString(const char* str, intptr_t* startPos, intptr_t* endPos, 247 | bool ignoreCase, bool wholeWord, bool regExp); 248 | void toggleFolding(intptr_t lineNum); 249 | void foldAll(int foldAction); 250 | void onStyleNeeded(SCNotification* notify); 251 | void onNewPosition(); 252 | void onHotspotClick(SCNotification* notify); 253 | void onDoubleClick(intptr_t pos); 254 | void onMarginClick(SCNotification* notify); 255 | bool onKeyPress(WORD keyCode, bool alt); 256 | void onTabChange(); 257 | void onCloseTab(); 258 | void closeAllTabs(); 259 | void onResize(int width, int height); 260 | void onMove(); 261 | void onSearch(bool reverseDir = false, bool keepFocus = false); 262 | 263 | static std::unique_ptr RW; 264 | 265 | static HWND _hSci; 266 | static SciFnDirect _sciFunc; 267 | static sptr_t _sciPtr; 268 | 269 | HWND _hWnd; 270 | HWND _hTab; 271 | HHOOK _hKeyHook; 272 | Tab* _activeTab; 273 | 274 | HWND _hSearch; 275 | HWND _hSearchTxt; 276 | HWND _hRE; 277 | HWND _hIC; 278 | HWND _hWW; 279 | HWND _hUp; 280 | HWND _hDown; 281 | HFONT _hSearchFont; 282 | HFONT _hBtnFont; 283 | 284 | int _searchTxtHeight; 285 | 286 | bool _lastRE; 287 | bool _lastIC; 288 | bool _lastWW; 289 | CText _lastSearchTxt; 290 | }; 291 | 292 | } // namespace GTags 293 | -------------------------------------------------------------------------------- /src/SearchWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief Search input window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2014-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include "Common.h" 32 | #include "GTags.h" 33 | #include "CmdDefines.h" 34 | 35 | 36 | namespace GTags 37 | { 38 | 39 | /** 40 | * \class SearchWin 41 | * \brief 42 | */ 43 | class SearchWin 44 | { 45 | public: 46 | static void Register(); 47 | static void Unregister(); 48 | 49 | static void Show(CmdId_t cmdId, CompletionCB complCB, const TCHAR* hint = nullptr, 50 | bool enRE = true, bool enIC = true); 51 | static void Close(); 52 | 53 | static bool IsFocused(HWND hWnd = NULL) 54 | { 55 | if (hWnd == NULL) 56 | hWnd = GetFocus(); 57 | 58 | return (SW && (SW->_hWnd == hWnd || IsChild(SW->_hWnd, hWnd))); 59 | }; 60 | 61 | static bool Activate() 62 | { 63 | if (SW) 64 | { 65 | SetFocus(SW->_hSearch); 66 | return true; 67 | } 68 | 69 | return false; 70 | }; 71 | 72 | SearchWin(CmdId_t cmdId, CompletionCB complCB) : 73 | _cmdId(cmdId), _complCB(complCB), _cmd(NULL), _hKeyHook(NULL), _cancelled(true), _keyPressed(0), 74 | _completionStarted(false), _completionDone(false), _initialCompl(false) {} 75 | ~SearchWin(); 76 | 77 | private: 78 | static const TCHAR cClassName[]; 79 | static const int cWidth; 80 | static const int cComplAfter; 81 | 82 | static LRESULT CALLBACK keyHookProc(int code, WPARAM wParam, LPARAM lParam); 83 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 84 | 85 | static void halfComplete(const CmdPtr_t&); 86 | static void endCompletion(const CmdPtr_t&); 87 | 88 | SearchWin(const SearchWin&); 89 | SearchWin& operator=(const SearchWin&) = delete; 90 | 91 | HWND composeWindow(HWND hOwner, const TCHAR* hint, bool enRE, bool enIC); 92 | void reinit(CmdId_t cmdId, CompletionCB complCB, const TCHAR* hint, bool enRE, bool enIC); 93 | 94 | void startCompletion(); 95 | void hideDropDown(); 96 | void clearCompletion(); 97 | void filterComplList(); 98 | 99 | void saveSearchOptions(); 100 | void onEditChange(); 101 | void onOK(); 102 | inline void onTabPress(); 103 | 104 | static std::unique_ptr SW; 105 | 106 | CmdId_t _cmdId; 107 | CompletionCB _complCB; 108 | 109 | CmdPtr_t _cmd; 110 | 111 | HWND _hWnd; 112 | HWND _hSearch; 113 | HWND _hRE; 114 | HWND _hIC; 115 | HWND _hOK; 116 | HFONT _hTxtFont; 117 | HFONT _hBtnFont; 118 | HHOOK _hKeyHook; 119 | bool _cancelled; 120 | int _keyPressed; 121 | bool _completionStarted; 122 | bool _completionDone; 123 | ParserPtr_t _completion; 124 | 125 | bool _initialCompl; 126 | }; 127 | 128 | } // namespace GTags 129 | -------------------------------------------------------------------------------- /src/SettingsWin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief GTags config window 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2015-2024 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include "DbManager.h" 31 | #include "Config.h" 32 | #include "CmdDefines.h" 33 | #include "GTags.h" 34 | 35 | 36 | class CPath; 37 | 38 | 39 | namespace GTags 40 | { 41 | 42 | /** 43 | * \class SettingsWin 44 | * \brief 45 | */ 46 | class SettingsWin 47 | { 48 | public: 49 | static void Show(); 50 | static void Show(const DbHandle& db); 51 | 52 | SettingsWin(); 53 | ~SettingsWin(); 54 | 55 | private: 56 | /** 57 | * \struct Tab 58 | * \brief 59 | */ 60 | struct Tab 61 | { 62 | Tab(const DbHandle db = DbHandle(NULL)); 63 | ~Tab(); 64 | Tab& operator=(const Tab&) = delete; 65 | 66 | DbHandle _db; 67 | DbConfig _cfg; 68 | 69 | bool _updateDb; 70 | }; 71 | 72 | 73 | static const TCHAR cClassName[]; 74 | static const TCHAR cHeader[]; 75 | static const int cBackgroundColor; 76 | static const int cFontSize; 77 | 78 | static bool createWin(); 79 | 80 | static void dbWriteReady(const CmdPtr_t& cmd); 81 | static void createDefDbCB(const CmdPtr_t& cmd); 82 | static void createLibDbCB(const CmdPtr_t& cmd); 83 | 84 | static LRESULT CALLBACK keyHookProc(int code, WPARAM wParam, LPARAM lParam); 85 | static LRESULT APIENTRY wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 86 | 87 | SettingsWin(const SettingsWin&); 88 | 89 | HWND composeWindow(HWND hOwner); 90 | 91 | Tab* getTab(int i = -1); 92 | bool isDbOpen(const CPath& dbPath); 93 | void onUpdateDefDb(); 94 | void onUpdateLibDb(); 95 | void onTabChange(); 96 | void onSave(); 97 | void fillTabData(); 98 | void readTabData(); 99 | bool saveDbConfig(Tab* tab); 100 | bool saveSettings(const Settings& newSettings); 101 | bool saveTab(Tab* tab); 102 | void fillDefDb(const CPath& defDb); 103 | void fillMissing(HWND SettingsWin::*editCtrl, const CText& entry); 104 | inline void fillLibDb(const CPath& lib); 105 | inline void fillPathFilter(const CPath& filter); 106 | 107 | bool createDatabase(CPath& dbPath, CompletionCB complCB); 108 | 109 | static std::unique_ptr SW; 110 | 111 | Tab* _activeTab; 112 | 113 | HWND _hWnd; 114 | HWND _hKeepSearchOpen; 115 | HWND _hTrigAutocmplEn; 116 | HWND _hTrigAutocmplAfter; 117 | HWND _hEnDefDb; 118 | HWND _hSetDefDb; 119 | HWND _hUpdDefDb; 120 | HWND _hDefDb; 121 | HWND _hTab; 122 | HWND _hInfo; 123 | HWND _hParserInfo; 124 | HWND _hParser; 125 | HWND _hAutoUpdDb; 126 | HWND _hEnLibDb; 127 | HWND _hAddLibDb; 128 | HWND _hUpdLibDbs; 129 | HWND _hLibDbs; 130 | HWND _hEnPathFilter; 131 | HWND _hAddPathFilter; 132 | HWND _hPathFilters; 133 | HWND _hSave; 134 | HWND _hCancel; 135 | 136 | HHOOK _hKeyHook; 137 | 138 | HFONT _hFont; 139 | HFONT _hFontInfo; 140 | }; 141 | 142 | } // namespace GTags 143 | -------------------------------------------------------------------------------- /src/StrUniquenessChecker.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * \brief String uniqueness checker class - checks if a string passes through the class for the first time. 4 | * 5 | * \author Pavel Nedev 6 | * 7 | * \section COPYRIGHT 8 | * Copyright(C) 2016 Pavel Nedev 9 | * 10 | * \section LICENSE 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as published 13 | * by the Free Software Foundation. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 | * for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program. If not, see . 22 | */ 23 | 24 | 25 | #pragma once 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | /** 34 | * \class StrUniquenessChecker 35 | * \brief 36 | */ 37 | template 38 | class StrUniquenessChecker 39 | { 40 | public: 41 | StrUniquenessChecker() {} 42 | ~StrUniquenessChecker() {} 43 | 44 | bool IsUnique(const CharType* ptr) 45 | { 46 | if (!ptr) 47 | return false; 48 | 49 | std::basic_string str(ptr); 50 | std::hash> hash; 51 | 52 | return _set.insert(hash(str)).second; 53 | } 54 | 55 | private: 56 | StrUniquenessChecker(const StrUniquenessChecker&) = delete; 57 | const StrUniquenessChecker& operator=(const StrUniquenessChecker&) = delete; 58 | 59 | std::unordered_set _set; 60 | }; 61 | -------------------------------------------------------------------------------- /src/nppgtags.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnedev/nppgtags/dce8041e1b16ab04d1a3e380affd704ab1f06e1d/src/nppgtags.ico -------------------------------------------------------------------------------- /src/nppgtags.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resource.h" 3 | 4 | 5 | VS_VERSION_INFO VERSIONINFO 6 | FILEVERSION VER_VERSION 7 | PRODUCTVERSION VER_VERSION 8 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 9 | FILEFLAGS VER_DEBUG 10 | FILEOS VOS_NT_WINDOWS32 11 | FILETYPE VFT_DLL 12 | FILESUBTYPE VFT2_UNKNOWN 13 | BEGIN 14 | BLOCK "StringFileInfo" 15 | BEGIN 16 | BLOCK "040904B0" 17 | BEGIN 18 | VALUE "CompanyName", VER_AUTHOR 19 | VALUE "FileDescription", VER_DESCRIPTION 20 | VALUE "FileVersion", VER_VERSION_STR 21 | VALUE "InternalName", VER_DLLFILENAME 22 | VALUE "LegalCopyright", VER_COPYRIGHT 23 | VALUE "OriginalFilename", VER_DLLFILENAME 24 | VALUE "ProductName", VER_PRODUCT_NAME 25 | VALUE "ProductVersion", VER_VERSION_STR 26 | END 27 | END 28 | 29 | BLOCK "VarFileInfo" 30 | BEGIN 31 | VALUE "Translation", 0x409, 0x4B0 32 | END 33 | END 34 | 35 | IDI_PLUGINPANEL ICON DISCARDABLE "nppgtags.ico" 36 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | 6 | 7 | #define PLUGIN_NAME _T("NppGTags") 8 | 9 | #define VER_VERSION 5,2,0,0 10 | #define VER_VERSION_STR _T("5.2.0\0") 11 | 12 | #define VER_DESCRIPTION _T("GTags plugin for Notepad++\0") 13 | 14 | #define VER_AUTHOR _T("Pavel Nedev\0") 15 | #define VER_COPYRIGHT _T("Copyright (C) 2014-2024 Pavel Nedev\0") 16 | #define VER_URL _T("https://github.com/pnedev/nppgtags\0") 17 | #define VER_USER_GUIDE _T("https://github.com/pnedev/nppgtags/blob/master/README.md\0") 18 | 19 | #define VER_DLLFILENAME PLUGIN_NAME _T(".dll\0") 20 | 21 | #ifndef _DEBUG 22 | #define VER_DEBUG 0 23 | #else 24 | #define VER_DEBUG VS_FF_DEBUG 25 | #endif 26 | 27 | #ifndef _WIN64 28 | #define VER_PRODUCT_NAME PLUGIN_NAME _T(" (32-bit)\0") 29 | #else 30 | #define VER_PRODUCT_NAME PLUGIN_NAME _T(" (64-bit)\0") 31 | #endif 32 | 33 | #define IDI_PLUGINPANEL 2501 34 | --------------------------------------------------------------------------------