
- Code: Select all
# Файл: nncron_wordslike.tab
# Автор: dothen
# Дата: 07.05.2017
# Версия: 2.12
# Описание:
# Поиск слов в словаре nnCron и вывод на экран.
# Переделанный WORDS-LIKE
# Подключить плагин extwords.spf
# Подключить кронтаб nncron_extwords2.tab (http://www.nncron.ru/forums/viewtopic.php?f=5&t=13361#p35725)
# ------------------
# Если во входной строке есть пробелы и т.п. то берется первое слово в качестве фрагмента.
# Длинный фрагмент yкорачивается до 60 символов.
# Если найдено 50 и больше слов тогда список выводится сразу в блокнот.
# Если для поиска задать пустую строку или пробелы то получим все слова из словаря.
# В конце списка добавляется статистика.
# Чтобы выполнить поиск без учета регистра надо нажать Shift
# Можно искать с использованием регулярных выражений. Примеры: /get.*name/i /^SAVE/ /rror$/
# Горячие клавиши:
# Win+W - Появляется диалоговое окно с предложением ввести часть слова. Если в буфере обмена есть текст то в поле ввода будут вставлены первые символы (максимум 60 если не было пробела).
# Win+Q - То же самое, только после отпускания клавиши Win автоматически выводится результат поиска (если окно имеет фокус).
# Можно подержать клавишу Win нажатой и переключить учет регистра (Shift), или закрыть окно, или деактивировать(мышкой или Win+(1-9) и т.п.).
# Задача сохраняет историю введенных слов.
# Открывается история в виде меню, двумя способами:
# 1) Down(стрелка вниз) когда окно с приглашением ввести слово активно.
# 2) LBM(левая клавиша мыши) в этом же окне на кнопке [развернуть].
# Константа wlmaxhistory устанавливает масштаб истории.
# Одновременно могут работать несколько задач (после вывода в блокнот задача завершается).
# Константа wlmaxcounter устанавливает число одновременно работающих задач и блокнотов.
# Закрытие окна с нажатой Shift вызывает закрытие всех окон и блокнотов, открытых из задачи.
# Задача не изменяет содержимое буфера обмена а только копирует из него текст.
<%
SCONSTANT WLWindowTitle1 Поиск слов в словаре nnCron
SCONSTANT WLWindowTitle2 Список найденных слов:
WinGVI?
[IF] \ Если Vista или выше.
SCONSTANT NotepadTitle Безымянный — Блокнот
[ELSE] \ Если XP или ниже.
SCONSTANT NotepadTitle Безымянный - Блокнот
[THEN]
USER-VALUE WLFOUND \ Список найденных слов.
USER WLCOUNT \ Количество найденных слов.
USER WLALLWORDS \ Количество всех слов в словаре.
USER WLFULLWORD \ Количество точно соответствующих слов.
64 USER-ARRAY WLFRAGMENT
10 CONSTANT wlmaxhistory \ Число слов в истории.
4 CONSTANT wlmaxcounter \ Число одновременно работающих задач.
0 VALUE <cron-node> \ Адрес структуры CRON-NODE основной задачи. Для доступа из другой задачи, вместо вектора.
: WLTaskCounter ( -- n ) <cron-node> CRON-COUNTER @ ; \ Для работы в слове (WLWatchHKey), т.к. задача определена после него, т.е. имени еще нет в словаре.
: WLMaxNotepads? ( -- ? )
PAD 0!
FOR-WINDOWS: "%WLWindowTitle2%*"
PAD 1+! \ Вместо PAD можно взять <FOUND-WINDOW> в качестве счетчика.
;FOR-WINDOWS
PAD @ wlmaxcounter < 0=
;
: icase? ( -- ? ) VK_SHIFT KEY-PRESSED? ; \ Игнорировать регистр если TRUE
: XT_SEARCH ( -- xt ) icase? IF ['] ISEARCH ELSE ['] SEARCH THEN ;
: ReMatch ( a1 u1 amask umask -- 0 0 ? ) RE-MATCH 0 0 ROT ;
: XT-RE|SEARCH ( -- xt )
WLFRAGMENT DUP C@ + C@ [CHAR] / =
WLFRAGMENT DUP C@ + 1- C@ [CHAR] / = OR
WLFRAGMENT 1+ C@ [CHAR] / = AND
IF ['] ReMatch ELSE XT_SEARCH THEN
;
: +WLFOUND ( a u -- ) WLFOUND +SPLACE ;
: WLADDREPORT ( xt -- )
>R
S" ____________" +WLFOUND
CRLF +WLFOUND
S" Найдено слов:" +WLFOUND
HTAB +WLFOUND
WLCOUNT @ N>S +WLFOUND
R> ['] ReMatch =
IF
HTAB +WLFOUND S" Регулярное выражение" +WLFOUND
ELSE
icase? IF HTAB +WLFOUND S" Без учета регистра" +WLFOUND THEN
THEN
CRLF +WLFOUND
S" Точных слов:" +WLFOUND
HTAB +WLFOUND
WLFULLWORD @ N>S +WLFOUND
CRLF +WLFOUND
S" Фрагмент:" +WLFOUND
HTAB +WLFOUND
WLFRAGMENT COUNT +WLFOUND
HTAB +WLFOUND
S" Длина: " +WLFOUND
WLFRAGMENT C@ N>S +WLFOUND
CRLF +WLFOUND
S" Всего слов:" +WLFOUND
HTAB +WLFOUND
WLALLWORDS @ N>S +WLFOUND
;
: (WordsLike) ( -- )
WLCOUNT 0! WLALLWORDS 0!
WLFOUND 0! WLFULLWORD 0!
XT-RE|SEARCH >R
CONTEXT @ @
BEGIN ?DUP WHILE
DUP COUNT WLFRAGMENT COUNT R@ EXECUTE
IF
2 PICK 1+ WLFRAGMENT C@ D= IF HTAB +WLFOUND WLFULLWORD 1+! THEN
DUP COUNT +WLFOUND CRLF +WLFOUND
WLCOUNT 1+!
ELSE
2DROP
THEN WLALLWORDS 1+!
CDR
REPEAT R> WLADDREPORT
;
: WordsLike2Notepad ( -- )
WLMaxNotepads? IF S" Открыть блокнот?" 5 0 TQUERY 0= IF EXIT THEN THEN
S" notepad.exe" START-APP
20 0 DO
50 PAUSE
NotepadTitle DROP Z" Notepad" FindWindowA ?DUP \ Проверку делаем в цикле для того чтобы пауза перед выводом текста была минимальная.
IF
WLWindowTitle2 >ZPAD WLFRAGMENT COUNT +ZPAD
S" " +ZPAD WLFULLWORD @ N>S +ZPAD
S" / " +ZPAD WLCOUNT @ N>S +ZPAD
>R ZPAD R@ SetWindowTextA DROP \ Меняем заголовок чтобы при запуске нескольких блокнотов FindWindowA находила последний открытый блокнот.
0 Z" Edit" 0 R> FindWindowExA >R
WLFOUND SCOUNT DROP 0 12 R> SendMessageA DROP \ #define WM_SETTEXT 12
LEAVE
THEN
LOOP
;
WINAPI: SetDlgItemTextA USER32.DLL
: WLSetButtonText ( -- )
10 0 DO
10 PAUSE
WLWindowTitle1 DROP Z" #32770" FindWindowA ?DUP \ Проверку делаем в цикле для того чтобы пауза перед выводом текста была минимальная.
IF
>R WLWindowTitle2 DROP R@ SetWindowTextA DROP \ Меняем заголовок чтобы при запуске нескольких задач FindWindowA находила последний открытый диалог.
Z" Закрыть" 2 R@ SetDlgItemTextA DROP \ #define IDCANCEL 2
Z" Назад" 10 R@ SetDlgItemTextA DROP \ #define IDTRYAGAIN 10
Z" В блокнот" 11 R> SetDlgItemTextA DROP \ #define IDCONTINUE 11
LEAVE
THEN
LOOP
;
VECT WordsLikeInput
VARIABLE wlcloseall
\ Закрывает все окна открытые задачей, в том числе блокноты.
: WLWinCloseAll ( -- )
wlcloseall @
IF
WLWindowTitle1 DROP Z" spfwinclass" WIN-NAME-CLOSE-ALL
WLWindowTitle2 DROP Z" #32770" WIN-NAME-CLOSE-ALL
ALL WIN-CLOSE: "%WLWindowTitle2%*" \ Блокноты
THEN
;
: WordsLike2Messagebox ( -- )
['] WLSetButtonText EXECUTE-LAUNCH
0x40106 WLWindowTitle1 DROP \ MB_CANCELTRYCONTINUE+MB_DEFBUTTON2+MB_TOPMOST
\ WLFOUND SCOUNT DROP 0 MessageBoxA
WLFOUND CELL+ 0 MessageBoxA
CASE
11 OF WordsLike2Notepad ENDOF \ Продолжить (В блокнот)
10 OF WordsLikeInput ENDOF \ Повторить (Назад)
2 OF WLWinCloseAll ENDOF \ Отмена (Закрыть)
DUP OF NOOP ENDOF
ENDCASE
;
: WLGetFragment ( a u -- )
LTRIM \ Удаляем из начала пробелы, табуляции, переводы строк.
CropAfterWord \ Берем первое слово.
60 MIN WLFRAGMENT PLACE0 \ Укорачиваем длинный фрагмент.
;
\ mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
fVAR wordslike_history \ Файловая переменная для хранения истории запросов.
: WLHistoryManage ( -- )
WLFRAGMENT C@ 0= IF EXIT THEN
WLFOUND 0!
WLFRAGMENT COUNT +WLFOUND
CRLF +WLFOUND
wordslike_history OVER >R
FOR-LINES
LINE-NUMBER wlmaxhistory = IF LINE-EXIT EXIT THEN \ LINE-EXIT - выход из BEGIN а EXIT - выход из [NONAME NONAME]
FOUND-LINE WLFRAGMENT COUNT COMPARE
IF FOUND-LINE +WLFOUND CRLF +WLFOUND ELSE LINE-NUMBER 1- TO LINE-NUMBER THEN
;FOR-LINES
WLFOUND SCOUNT TO wordslike_history
R> FREE DROP \ Если файла нет то FREE дает ошибку т.к. память не выделяется (см. слово fVAR).
;
\ -------------------- Меню --------------------
0 VALUE wlhwnd
\ Вставляет текст в поле ввода.
: WLSetInputText ( az -- )
0 Z" Edit" 0 wlhwnd FindWindowExA >R
0 12 R@ SendMessageA DROP \ #define WM_SETTEXT 12
R> WinActivate End
;
: WLHistoryMenuBuild ( -- )
POPUPMENU
wordslike_history OVER >R
FOR-LINES
ZPAD FOUND-LINE 2DUP >ZPAD SWAP MENUITEM
;FOR-LINES
END-MENU
RunMenu
IF MENUITEM-TEXT DROP WLSetInputText THEN
R> FREE DROP
0 TO wlhwnd
;
: WLHistoryMenuShow ( -- )
['] WLHistoryMenuBuild EXECUTE-LAUNCH
BEGIN 100 PAUSE wlhwnd 0= UNTIL
;
: WLWinActive? ( a u -- ? )
GetForegroundWindow DUP TO wlhwnd GET-WTEXT COMPARE 0=
;
\ Открывает меню с историей поиска, мышью на кнопке [развернуть] (9).
: WLHistoryMenuM ( -- )
VK_LBUTTON KEY-PRESSED?
IF
WLWindowTitle1 WLWinActive?
IF
wlhwnd SEND-WM_NCHITTEST 9 = IF WLHistoryMenuShow THEN
THEN
THEN
;
\ Открывает меню с историей поиска, по горячей клавише (Стрелка вниз).
: WLHistoryMenuK ( -- )
VK_DOWN KEY-PRESSED?
IF
WLWindowTitle1 WLWinActive?
IF
wlhwnd WIN-RECT DROP MOUSE-MOVE DROP \ Мышь в правый верхний угол окна.
WLHistoryMenuShow
VK_DOWN WAIT-KUP
THEN
THEN
;
\ mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
: WordsLike ( a u -- )
WLGetFragment
100 Kb ALLOCATE THROW DUP >R TO WLFOUND \ При поиске через "Повторить", будет выделен новый буфер. Поэтому запоминаем адрес текущего буфера в >R чтобы освободить память.
WLHistoryManage
(WordsLike)
WLCOUNT @ 50 < \ Если найдено 50 и больше слов то выводим список сразу в блокнот.
IF WordsLike2Messagebox ELSE WordsLike2Notepad THEN
500 PAUSE
R> FREE THROW
;
: WLPromptText ( -- a u )
CRLF S" Введите часть искомого слова" S+
icase? IF S" Поиск без учета регистра" 2SWAP S+ THEN
;
:NONAME ( -- )
WLWindowTitle1 WLPromptText
WLFRAGMENT COUNT 0 WIN-INPUT-TEXT 0=
IF
WordsLike
ELSE
WLWinCloseAll
THEN
; TO WordsLikeInput
\ Находит диалоговое окно WIN-INPUT-TEXT
: WLFindWinInput ( 0 | hwnd -- 0 | nexthwnd )
>R WLWindowTitle1 DROP Z" spfwinclass" R> 0 FindWindowExA
;
\ Меняет текст приглашения в диалоговом окне WIN-INPUT-TEXT: при нажатии Shift
: WLSetPromptText ( -- ) { \ hwnd -- }
WLWindowTitle1 WLWinActive? IFNOT EXIT THEN
0 WLFindWinInput TO hwnd
BEGIN hwnd WHILE
0 Z" Static" 0 hwnd FindWindowExA >R
WLPromptText DROP 0 12 R> SendMessageA DROP \ #define WM_SETTEXT 12
hwnd WLFindWinInput TO hwnd
REPEAT
;
\ Проверка и обработка нажатий хоткеев и хоткликов.
: (WLWatchHKey) ( -- ) { \ flagcase -- }
500 PAUSE
icase? TO flagcase \ Начальное состояние переключателя.
BEGIN WLTaskCounter WHILE
50 PAUSE
icase? DUP flagcase <>
IF DUP TO flagcase WLSetPromptText THEN DROP
WLHistoryMenuK
WLHistoryMenuM
VK_SHIFT KEY-PRESSED? wlcloseall !
REPEAT
;
: WLWatchHKey ( -- )
CUR-NODE CRON-COUNTER @ 1 = \ Если запущен первый экзепляр задачи.
IF
CUR-NODE TO <cron-node>
['] (WLWatchHKey) EXECUTE-LAUNCH
THEN
;
: (WORDS~LIKE) ( -- )
WLWatchHKey
WLTaskCounter wlmaxcounter > IF EXIT THEN
ENU LngActivate
CLIPBOARD@ WLGetFragment
WordsLikeInput
;
%>
#( CLASSIC-TASK-#-WORDSLIKE
\ NoActive
WatchHotKey: "$W" \ Win+W
CUR-NODE TO <cron-node>
Action:
(WORDS~LIKE)
)#
#( CLASSIC-TASK-#-WORDSLIKE2
\ NoActive
SingleInstance
WatchHotKey: "$Q" \ Win+Q
Action:
CLASSIC-TASK-#-WORDSLIKE LAUNCH
VK_LWIN WAIT-KUP \ Можно подержать клавишу Win нажатой и переключить учет регистра (Shift), или закрыть окно, или деактивировать(мышкой или Win+(1-9) и т.п.).
WLWindowTitle1 WLWinActive? IF Enter THEN
)#
<%
\ Для запуска из консоли.
\ : WORDS~LIKE ( -- )
\ CLASSIC-TASK-#-WORDSLIKE LAUNCH
\ 100 PAUSE
\ 0 WLFindWinInput
\ WinActivate
\ ;
%>
Подключить плагин extwords.spf
Подключить кронтаб nncron_extwords2.tab