
Программист часто копирует и вставляет, переименовывает и рефакторит. Выделил (подсветил) мышкой переменную или функцию и вот бы сразу видеть их количество в статусной строке. Увы, стандартный поиск (Ctrl+F) требует лишние клики.
Мой небольшой Python-скрипт для Notepad++ по дабл-клику
отображает в Status-Bar количество вхождений,
частичных или полных, с учетом регистра и без.
Диклеймер: Даже писателю доставляет наслаждение от удовольствия нагромождать многократное повторение одних и тех же тавтологий по нескольку раз, используя сильно ограниченный набор слов из заданного словаря предыдущего набора многократный повторений одних и тех слов /s.
Есть ли альтернативы?
Три неудобных способа:
Notepad++ умеет подсвечивать выделенный фрагмент текста при двойном клике, но а сколько раз это встречается в файле? Чтобы увидеть заветную цифру, нужно нажать Ctrl+F, а затем кнопку
Count(илиMark All).

NppTextFX2 плагин выводит статистику в отдельное окно, но появившееся окно модальное, его каждый раз нужно закрывать, чтобы вернуться к коду.

Еще есть такой же Summary Feature.

Страничка , описывающие все три способа с картинками.
Подготовка.
установить плагин Python Script
С помощью Python Script можно производить любые операции с текстом, переключать вкладки и управлять интерфейсом Notepad++.
Откройте Plugins -> Plugins Admin ..
Найдите и установите Python Script. Как установить и запустить скрипт в Python Script?
После перезапуска Notepad++, выберите Plugins -> Python Script -> New Script.
Код скрипта.
Выбрав в меню Notepad++ Plugins -> Python Script -> New Script, вставляем код скрипта:
код скрипта SmartHighlightingCounterInStatusBar.py
# -*- coding: utf-8 -*- from Npp import editor, notepad, SCINTILLANOTIFICATION, UPDATE, STATUSBARSECTION import re # Scintilla (the engine behind Notepad++) # 1. Define Task A def get_selection_count(): if editor.getSelections() != 1 or editor.getSelectionEmpty(): return "" try: content = editor.getText().decode('utf-8') selected = editor.getSelText().decode('utf-8') patt_p = re.escape(selected) patt_w = ur"\b" + patt_p + ur"\b" matches_p = re.findall(patt_p, content, re.UNICODE | re.IGNORECASE) matches_w = re.findall(patt_w, content, re.UNICODE | re.IGNORECASE) ip = len(matches_p) iw = len(matches_w) # сколько из найденных совпали с оригиналом по регистру sp = sum(1 for m in matches_p if m == selected) sw = sum(1 for m in matches_w if m == selected) return "w[≡{},∀{}], p…≡{},∀{}…".format(sw, iw, sp, ip) except Exception as e: return str(e) + " - Err(exc)" return "" # "nothing selected" is might flicker or look like "clutter" # 2. Define Task B # def get_other_script_info(): # return "OtherInfo" # 3. Master Callback that manages the Status Bar def master_status_callback(args): if not (args['updated'] & (UPDATE.SELECTION | UPDATE.CONTENT)): return match_info = get_selection_count() notepad.setStatusBar(STATUSBARSECTION.DOCSIZE, match_info) # other_info = get_other_script_info() if 'MY_MASTER_STATUS_LOADED' not in globals(): editor.callback(master_status_callback, [SCINTILLANOTIFICATION.UPDATEUI]) MY_MASTER_STATUS_LOADED = True print("Multi-Script Status Bar Loaded")
"Архитектура" решения.
1. Master Callback
Заложил поддержку нескольких колбэков в скрипт, что б не вызывать конфликты, например:
def get_other_script_info(): ... other_info = get_other_script_info() notepad.setStatusBar(STATUSBARSECTION.*, other_info)
2. Notepad++ vs system Python.
Плагин Python Script жестко привязан к встроенному интерпретатору (версия 2.7). В конфигураторе есть галка Prefer installed Python library.. gave to copy.., отметив которую чудо не произошло. А копированием я не стал заниматься. Гугль пишет, не получится использовать библиотеки из своего системного Python 3.х, поэтому приходится мириться с особенностями «двойки», такими как обязательные префиксы u"" и decode('utf-8').
3. Regex в Scintilla vs re.
Долго экспериментировал с движком Scintilla, куча проблем , начиная с UTF8. Отказался от этого капризного зверя (editor.research) в пользу нативного модуля Python re. Это гарантирует работу с кириллицей, регулярками и корректную обработку границ слов.
Изначально я пытался использовать editor.research. Но движок Scintilla в Notepad++ 8.x (основанный на Boost.Regex) ведет себя непредсказуемо с кириллицей: то требует флаг 0x00800000, то игнорирует границы слов \b, то падает с ошибкой Invalid or unterminated... при попытке передать UTF-8 байты. Нативный модуль re с флагом re.UNICODE решил все проблемы разом.
4. CamelCaseStyle и snake_case_style.
Была идея добавить автоматическое определение стиля написания (например, выделяешь _btn в _btn110Clk - и что искать _btn или _Btn, или btn и не BTN). На практике критерии оказались слишком зыбкими:
Selection must start with an Uppercase... cannot contain underscores...
Слишком много «если» (особенно с цифрами), которые только запутали бы понимание, что именно подсчитывать.
Лаконичный «Partial/Whole» (частично и полное слово), «Case Sensitive / Case Insensitive» (с учетом регистра и без) поиск оказался гораздо надежнее.
5. Status Bar.
Я выбрал секцию STATUSBARSECTION.DOCSIZE. Забавно, до написания статьи не знал, что по ним можно кликать :-)
Всего в Python Script 6 шт STATUSBARSECTION
0. DOCTYPE: Тип документа (Язык). (например, Python file или Hyper Text Markup Language file). Двойной клик по этой секции открывает меню выбора языков. 1. DOCSIZE: Длина файла в символах (length) и количество строк (lines). При двойном клике открывается то самое окно Summary. 2. CURPOS: Номер текущей строки (Ln), колонки (Col), позиции курсора (Pos). При выделении: и количество выделенных символов (Sel). Двойной клик - окно «Перейти к строке» (Go to Line). 3. EOL: Формат конца строки (EOL). Вынь CRLF, *nix LF, Яблоко CR. Клик - выбор. 4. UNICODE: Кодировка (UTF-8, ANSI, ..). Клик - выбор.. 5. TYPINGMODE: Режим ввода (INS вставка или OVR замена). Клик переключает режим.
Если писать в основную(первую) секцию, Notepad++ мгновенно затирает ваше сообщение информацией о строке/колонке при любом движении курсора. DOCSIZE - самое стабильное место.
Автозагрузка скрипта.
Чтобы скрипт запускался сам вместе с Notepad++:
1. Из меню Plugins -> Python Script -> Configuration.
2. Меняю Initialisation в значение ATSTARTUP.
3. Добавляю в startup.py (в папке плагина, C:\Program Files\Notepad++\plugins\PythonScript\scripts\startup.py ).
Добавить код в конец startup.py
import sys import os # 1. Get the AppData path from the Windows Environment appdata = os.environ.get('APPDATA') user_script_dir = os.path.join(appdata, "Notepad++", "plugins", "Config", "PythonScript", "scripts") # 2. Add it to sys.path if it's not already there if user_script_dir not in sys.path: sys.path.append(user_script_dir) # 3. Import your script try: import SmartHighlightingCounterInStatusBar print("Startup: SmartHighlightingCounterInStatusBar loaded.") except ImportError as e: print("Startup Error: Could not find the script. " + str(e)) except Exception as e: print("Startup Error: " + str(e))
Результат.
При выделении любого фрагмента текста сразу видно в Status Bar.
Например выделяем BTN в моем примере :
btn BTN onbtnClk onBTNClk onBTNClk onBTNClk _$_@_onBTNClk_@_$ рус РУС янируски яниРУСки яниРУСки яниРУСки _$_@_яниРУСки_@_$
В данном случае пример отображается как w[≡1,∀2], p…≡5,∀7… , где:
- w - whole, полное совпадение. Для отображения используются квадратные скобки:
- p - partial, частичное совпадение. Для отображения используются многоточия:
- ≡ - Case Sensitive, с учётом регистра символов.
- ∀ - Case Insensitive, без учёта регистра символов.
Полное совпадение (w[≡1,∀2]):
≡1 - 1 полное совпадение с учётом регистра
∀2 - 2 полных совпадения без учёта регистра
Частичное совпадение (p…≡5,∀7…):
≡5 - 5 частичных совпадений с учётом регистра
∀7 - 7 частичных совпадения без учёта регистра
Прим: Специфические символы выбраны для краткости, из-за лимита длины поля статусной строки. Использование слов сразу вылезает за границу. См. соседнее поле с выводом строки, колонки и позиции.

PS (в личку задавали вопросы).
Будет ли работать со всеми кодировками, когда указываешь decode('utf-8')? С win1251, с UTF16
Да, будет. Я отказался от регулярных выражений Scintilla. editor.getText().decode('utf-8') превращает «сырые» байты из Scintilla в полноценные Unicode-объекты. Далее re.UNICODE корректно обрабатывает \b с нац. кодировками
UTF-16 BE BOM

Win-1251

П��и подготовке статьи оставил лишнюю строчку other_info = get_other_script_info()
закоментил.
У меня не выделяются буквы, если они входят в другое слово. Это какой-то отдельный плагин?
Эта настройка в самом Notepad++ ( SmartHighlighting: Enable )

PS: Никаких рекламных ссылок на мой , тем более что его нет.Телеграм-канал
