📜 ⬆️ ⬇️

Plugin for working with Gist in Notepad ++

Once I needed to create a gist, and I also actively use Notepad ++. After finding the plug-in for working with gist in Notepad ++ I did not succeed (there is only under Sublime), I decided to write my own. And besides, it was a good experience in writing plugins and working with github api.
Immediately post a link to the source:
NppGist sources and the plugin itself: NppGist (to connect it, simply transfer the file to the plugins folder in the Notepad ++ folder).



Under Notepad ++, plug-ins can be written in several languages: C ++, Ada, Delphi, .NET, but I stopped at the latter because of the speed of development and because I know it better.
')
The following was used for development:
  1. NppPlugin.NET - Notepad ++ template plugin for .NET platform.
  2. ServiceStack.Text - JSON serialization and deserialization ( high performance and small size).
  3. hurl.it is a handy online tool for compiling and testing GET, POST, DELETE and other queries.
  4. NUnit - unit testing.

For those who are interested in knowing how to write plugins under Notepad ++, welcome under cat.

Plug-in initialization

Interaction with Notepad ++ occurs through Win32 messages. But, fortunately, a ready-made plug-in template with all messages, classes, and structures has already been written under .NET ( NppPlugin.NET.v0.5 ). It is worth noting that Platform taget must be installed in x86 , instead of the Any CPU by default, and also use .NET 4.0, otherwise the plugin will not work.

The plug-in is initialized in the CommandMenuInit and SetToolBarIcon methods . The first one adds items that will be visible in the plugin menu as follows:
PluginBase.SetCommand(OpenCommandId, "Open Gist", OpenGistCommand, new ShortcutKey(false, false, false, Keys.None)); 

There you can also assign key combinations for certain commands (they are not used in the developed plugin).

The OpenGistCommand method is already described by the developer, and you can do anything in it. For this command - open the window.

In the SetToolBarIcon method, you can add icons with plug-in commands to the Notepad ++ toolbar.
 toolbarIcons tbIcons = new toolbarIcons(); tbIcons.hToolbarBmp = tbLoad.GetHbitmap(); IntPtr pTbIcons = Marshal.AllocHGlobal(Marshal.SizeOf(tbIcons)); Marshal.StructureToPtr(tbIcons, pTbIcons, false); Win32.SendMessage(PluginBase.nppData._nppHandle, NppMsg.NPPM_ADDTOOLBARICON, PluginBase._funcItems.Items[OpenCommandId]._cmdID, pTbIcons); Marshal.FreeHGlobal(pTbIcons); 


Saving and loading settings

To save and load plugin parameters, the following methods are used. Strings can also be saved.
 saveLocally = Convert.ToBoolean(Win32.GetPrivateProfileInt("Settings", "saveLocally", 1, IniFileName)); ... Win32.WritePrivateProfileString("Settings", "SaveLocally", (Convert.ToInt32(saveLocally)).ToString(), Main.IniFileName); 


Execute commands in Notepad ++

In fact, Notepad ++ uses the Scintilla component, which is used in other text editors. Thus, messages for interaction are divided into Notepad ++ and Scintilla. All possible message codes are listed in the NppPluginNETHelper.cs file. Notepad ++ messages have the NPPM prefix and are used for commands related to working with files, menus, tabs, languages, etc. Scintilla messages, in turn, are associated directly with the text editor (insert, delete, select, visual styles, folding, scrolling, etc.).

Interception of Notepad ++ events

To intercept event messages in Notepad ++, the beNotified method in the UnmanagedExports.cs file is used . These messages have the NPPN prefix for Notepad ++ events (opening, closing a file, switching tabs) and SCN for Scintilla events (changing text). The truth in this plugin is not used.

A complete list and detailed description of the commands for Notepad ++ is here: Messages And Notifications . And for Scintilla here: ScintillaDoc .

Correct receipt of UTF8 text from Notepad ++

For some reason, it is impossible to get the text in the UTF8 format in the .NET shell of the plugin, although this encoding is the most common. Therefore, the following property was added, which made it possible to correctly read including the Russian text, which is used when saving the gist.
 public string lpstrTextUtf8 { get { _readNativeStruct(); int len = 0; while (Marshal.ReadByte(_sciTextRange.lpstrText, len) != 0) ++len; if (len == 0) return string.Empty; byte[] buffer = new byte[len]; Marshal.Copy(_sciTextRange.lpstrText, buffer, 0, buffer.Length); return Encoding.UTF8.GetString(buffer); } } 


Embedding assemblies

Notepad ++ downloads plugins from all .dll files in the plugins folder. Moreover, if the plugin from the dll failed to load, a message is displayed with the following content: The plugin is not compatible with the current version of Notepad ++ . Thus, if you copy its dependencies (in this case JSON) to this folder along with the plugin themselves, this will not be very correct. It was certainly possible to use a folder for them, but I used a more elegant solution, namely, combining all dependencies with the plugin assembly itself. And besides, one file is more convenient to distribute and copy.

So, in order for the plugin to occupy only one dll, third-party builds were marked as Embedded Resource , and then dynamically connected as follows:
 static Main() { AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler; } private static Assembly ResolveEventHandler(object sender, ResolveEventArgs args) { string resource = string.Format("{0}.{1}.dll", PluginName, args.Name.Remove(args.Name.IndexOf(','))); Assembly currentAssembly = Assembly.GetExecutingAssembly(); using (Stream stream = currentAssembly.GetManifestResourceStream(resource)) { var bytes = new byte[(int)stream.Length]; stream.Read(bytes, 0, (int)stream.Length); return Assembly.Load(bytes); } } 


You can read more about how this is done in the article on CodeProject: Load DLL From Embedded Resource .

You could, of course, use a third-party program to merge assemblies into one, ILmerge for example, but it would have to be applied after each build.

It is worth noting that since ServiceStack.Text is a NuGet build and is loaded during the first build after cloning the repository, the Prebuild event was used to copy it into the root folder of the NppGist project.

Github api

There is nothing interesting in the implementation of interaction with GitHub Api, except it is worth mentioning that AccessToken is used for authorization, which can be obtained on the website , which is then transmitted to all requests as an access_token parameter. Anonymous readers are not supported in the developed plugin. A complete list of API methods used is listed here: github gists api .

Conclusion

The window for saving a gist looks like this (the opening window is similar):


But first you need to enter your access token.

I hope that after my article, it will be easier for everyone to write plugins under Notepad ++. If you wish, join the development and use the plugin.

Source: https://habr.com/ru/post/215769/


All Articles