惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
Help Net Security
Help Net Security
P
Proofpoint News Feed
J
Java Code Geeks
爱范儿
爱范儿
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
Google DeepMind News
Google DeepMind News
H
Help Net Security
G
Google Developers Blog
Jina AI
Jina AI
Vercel News
Vercel News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
Lohrmann on Cybersecurity
S
Schneier on Security
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
Security Archives - TechRepublic
Security Archives - TechRepublic
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
GbyAI
GbyAI
B
Blog
O
OpenAI News
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News: Ask HN
Hacker News: Ask HN
TaoSecurity Blog
TaoSecurity Blog
腾讯CDC
MongoDB | Blog
MongoDB | Blog
M
MIT News - Artificial intelligence
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
Webroot Blog
Webroot Blog
Simon Willison's Weblog
Simon Willison's Weblog
Y
Y Combinator Blog
C
Cisco Blogs
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
AI
AI
W
WeLiveSecurity
aimingoo的专栏
aimingoo的专栏
The Register - Security
The Register - Security
Project Zero
Project Zero
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale

博客园 - Amonw's Weblog

.NET默认一个客户端对同一个服务器地址同时只能建立2个TCP连接 homekit2mqtt on DietPi .Net Trace->Listeners->Remove Oracle 12c client with .NET legacy Oracle driver Minimum setup for Apache+AD SSO Minimum configuration for openldap to proxy multiple AD into a single search base 排列组合算法(PHP) ASDM through site to site VPN - Amonw's Weblog PHP, LDAPS and Apache DFS security warning and use group policy to set up internet security zones Refresh recovery area usage data after manually deleting files under recovery area Create Oracle Enterprise Manager repository data after restore a database from another server Restore Oracle database to another server .PRT extension and multiple NX versions Fix network adapter not present problem in cloned CentOS NX 8.5 License Server Firewall Setting Cisco ASA intra-interface routing How to configure windows machine to allow file sharing with dns alias (CNAME) Install unifi controller on CentOS
Make Notepad++ auto close HTML/XML tags after the slash(the Dreamweaver way)
Amonw's Weblog · 2016-05-18 · via 博客园 - Amonw's Weblog

I've been looking for a Notepad++ plugin that can close HTML/XML tags after a slash just like the way Dreamweaver does for a long time.
The only things I could find(TextFX, XML Tools etc.) close the tags right after ">" is typed in, which was not what I wanted.
A couple days ago I found a plugin called Automation Scripts. It allows me to write scripts in C#, so I don't have to spend time learning how to write Notepad++ plugins.
So here you go:

//npp_shortcut Ctrl+Shift+Z

//Automation Scripts plugin needs to be installed for this to work
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using System;
using System.Windows.Forms;
using NppScripts;

public class Script : NppScript
{
    public Script()
    {
        this.OnNotification = (notification) =>
        {
            if(notification.nmhdr.code == (uint)SciMsg.SCN_CHARADDED)
            {
                doInsertHtmlCloseTag((char)notification.ch);
            }
        };
    }

    public override void Run()
    {
        checkInsertHtmlCloseTag();
    }

    bool doCloseTag;

    void checkInsertHtmlCloseTag()
    {
        doCloseTag = !doCloseTag;
        Win32.SendMessage(Npp.NppHandle, NppMsg.NPPM_SETMENUITEMCHECK, Plugin.FuncItems.Items[this.ScriptId]._cmdID, doCloseTag ? 1 : 0);
    }

    string GetStartTagName(string input)
    {
        Regex regex=new Regex(@"<[A-Za-z][A-Za-z0-9]*[^>]*[^\/]>|<[A-Za-z]>");
        if(!regex.IsMatch(input)) return "";
        StringBuilder result=new StringBuilder();
        int i=1;
        while(input[i]!=' ' && input[i]!='>' & i<input.Length)
        {
            result.Append(input[i]);
            i++;
        }
        return result.ToString();
    }

    string GetEndTagName(string input)
    {
        Regex regex=new Regex(@"<\/[A-Za-z][A-Za-z0-9]*[^>]*>");
        if(!regex.IsMatch(input)) return "";
        StringBuilder result=new StringBuilder();
        int i=2;
        while(input[i]!=' ' && input[i]!='>' & i<input.Length)
        {
            result.Append(input[i]);
            i++;
        }
        return result.ToString();
    }
    
    string GetSelection()
    {
        IntPtr hCurrentEditView = Npp.CurrentScintilla;
        StringBuilder result=new StringBuilder();
        Win32.SendMessage(hCurrentEditView,SciMsg.SCI_GETSELTEXT,0,result);
        return result.ToString();
    }
    
    int FindNextTag(int pos)
    {
        IntPtr hCurrentEditView = Npp.CurrentScintilla;
        string pattern=@"<\/?[A-Za-z][A-Za-z0-9]*[^>]*[^\/]>|<\/?[A-Za-z]>";
        Win32.SendMessage(hCurrentEditView, SciMsg.SCI_SETSEL, pos, pos);
        Win32.SendMessage(hCurrentEditView,SciMsg.SCI_SEARCHANCHOR,0,0);
        return (int)Win32.SendMessage(hCurrentEditView,SciMsg.SCI_SEARCHPREV,(int)SciMsg.SCFIND_REGEXP,pattern);
    }
    
    void doInsertHtmlCloseTag(char newChar)
    {
        LangType docType = LangType.L_TEXT;
        Win32.SendMessage(Npp.NppHandle, NppMsg.NPPM_GETCURRENTLANGTYPE, 0, ref docType);
        bool isDocTypeHTML = (docType == LangType.L_HTML || docType == LangType.L_XML || docType == LangType.L_PHP);
        if (doCloseTag && isDocTypeHTML && newChar=='/')
        {
            IntPtr hCurrentEditView = Npp.CurrentScintilla;
            int currentPos = (int)Win32.SendMessage(hCurrentEditView, SciMsg.SCI_GETCURRENTPOS, 0, 0);
            char lastChar=(char)Win32.SendMessage(hCurrentEditView,SciMsg.SCI_GETCHARAT,currentPos-2,0);
            StringBuilder insertString=new StringBuilder();
            if(lastChar=='<')
            {
                int pos=currentPos;
                Stack<string> stack=new Stack<string>();
                string tag;
                while(true)
                {
                    pos=FindNextTag(pos);
                    if(pos==-1)
                    {
                        Win32.SendMessage(hCurrentEditView, SciMsg.SCI_SETSEL, currentPos, currentPos);
                        return;
                    }
                    tag=GetSelection();
                    if(tag[1]=='/')
                    {
                        stack.Push(GetEndTagName(tag));
                    }
                    else
                    {
                        tag=GetStartTagName(tag);
                        if(stack.Count==0) 
                            break;
                        else
                        {
                            string endTag=stack.Pop();
                            while(tag!=endTag && stack.Count>0)
                            {
                                endTag=stack.Pop();
                            }
                            if(tag!=endTag) break;
                        }
                    }
                }
                insertString.Append(tag+">");
                Win32.SendMessage(hCurrentEditView, SciMsg.SCI_BEGINUNDOACTION, 0, 0);
                Win32.SendMessage(hCurrentEditView, SciMsg.SCI_SETSEL, currentPos, currentPos);
                Win32.SendMessage(hCurrentEditView, SciMsg.SCI_REPLACESEL, 0, insertString);
                Win32.SendMessage(hCurrentEditView, SciMsg.SCI_SETSEL, currentPos+insertString.Length, currentPos+insertString.Length);
                Win32.SendMessage(hCurrentEditView, SciMsg.SCI_ENDUNDOACTION, 0, 0);
            }
        }
    }
}