Last active
April 16, 2023 16:25
-
-
Save johnd0e/d79b55ce7fed21b921028a0dea49ed91 to your computer and use it in GitHub Desktop.
SmoothMove
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local Info = Info or package.loaded.regscript or function(...) return ... end --luacheck: ignore 113/Info | |
local nfo = Info { _filename or ..., | |
name = "SmoothMove"; | |
description = "Additional stops inside camelCase and snake_case words for CtrlLeft/Right, CtrlShiftLeft/Right, CtrlBS/Del/T"; --luacheck: ignore 631 | |
version = "1"; --http://semver.org/lang/ru/ | |
author = "jd"; | |
url = "https://forum.farmanager.com/viewtopic.php?t=13191"; | |
id = "9E2FCC08-B2FB-4CE4-A349-6BFB236BAEB9"; | |
minfarversion = {3,0,0,5460,0}; --LuaFAR 699: luautf8 | |
options = { | |
areas = "Editor Dialog Shell QView Info Tree", | |
side = "", -- "R"|"L"|"" | |
prio = 40, | |
word = "[%w_]", | |
stops = { | |
{"[%l%d]%u", "%u%f[%l%d]"}, --camelCase | |
{"[_]%w", "%w%f[_]"}, --snake_case (stop at 'c') | |
--{"_%f[%w]", "%w_"}, --snake_case (stop at '_') | |
}, | |
--[[ -- custom function to find word relative to cur pos | |
-- Example: work only if cursor is inside word | |
findWord = function(str,cur,key) --luacheck:ignore 212/key | |
return str:find("^%w",cur) and cur+1 | |
end, | |
--]] | |
--[[ -- custom condition | |
-- Example: work only when ScrollLock is on | |
condition = function(str,cur,key) --luacheck:ignore 212/str cur key | |
local SCROLL = 2 | |
if mf.flock(SCROLL,-1)==1 then return true end | |
end, | |
--]] | |
}; | |
--disabled = false; | |
} | |
if not nfo or nfo.disabled then return end | |
local O = nfo.options | |
local DIVS = Far.GetConfig("Editor.WordDiv"):gsub(".","%%%1") | |
local DIV = ("[%s]"):format(DIVS) | |
local DIVorSPACE = ("[%s]"):format(DIVS.."%s") | |
local function findStop(word,direction) | |
local pos | |
for _,stop in ipairs(O.stops) do | |
local p = select(2,word:find(stop[direction])) | |
if p then | |
pos = pos and math.min(p,pos) or p | |
end | |
end | |
return pos | |
end | |
local skipSpacesThenDivs = "^%s-"..DIV.."-"..O.word | |
local skipDivsAndSpaces = "^"..DIVorSPACE.."-"..O.word | |
local skip1Div = "^"..DIV.."?"..O.word | |
local skipAllDivs = "^"..DIV.."-"..O.word | |
local skips = { | |
CtrlRight =skipAllDivs, | |
CtrlShiftRight=skipDivsAndSpaces, | |
CtrlDel =skip1Div, | |
CtrlT =skip1Div, | |
CtrlLeft =skipSpacesThenDivs, | |
CtrlShiftLeft =skipDivsAndSpaces, | |
CtrlBS =skip1Div, | |
} | |
local function search(str,cur,key,direction) | |
local wordPos | |
if O.findWord then | |
wordPos = O.findWord(str,cur,key) | |
else | |
local skip = skips[key:match("^R?(.+)$"):gsub("RShift","Shift")] | |
wordPos = select(2,str:find(skip,cur+1)) | |
end | |
local word = wordPos and str:match(O.word.."+",wordPos) | |
local pos = word and findStop(word,direction) | |
return pos and pos+wordPos-1 | |
end | |
local Str, Cur, Pos -- common | |
local setStr, setPos | |
local F = far.Flags | |
local function getInfo(AKEY) | |
local info = far.AdvControl(F.ACTL_GETWINDOWINFO) | |
if info.Type==F.WTYPE_EDITOR then | |
Str = editor.GetString(nil,nil,3) | |
Cur = editor.GetInfo().CurPos | |
setStr = function(str) | |
editor.SetString(nil,nil,str) | |
end | |
setPos = function(pos) | |
editor.SetPosition(nil,nil,pos) | |
end | |
elseif info.Type==F.WTYPE_PANELS then | |
if AKEY=="CtrlT" then return end | |
Str = panel.GetCmdLine() | |
Cur = panel.GetCmdLinePos() | |
setStr = function(str) | |
panel.SetCmdLine(nil,str) | |
end | |
setPos = function(pos) | |
panel.SetCmdLinePos(nil,pos) | |
end | |
elseif info.Type==F.WTYPE_DIALOG then | |
local hDlg = info.Id | |
local focus = hDlg:send(F.DM_GETFOCUS) | |
local itemType = hDlg:send(F.DM_GETDLGITEM,focus)[1] | |
if itemType~=F.DI_EDIT then return end | |
Str = hDlg:send(F.DM_GETTEXT,focus) | |
Cur = hDlg:send(F.DM_GETEDITPOSITION,focus).CurPos | |
setStr = function(str) | |
hDlg:send(F.DM_SETTEXT,focus,str) | |
end | |
setPos = function(pos) | |
hDlg:send(F.DM_SETEDITPOSITION,focus,{CurPos=pos}) | |
end | |
else | |
return | |
end | |
local len = Str:len() | |
if Cur>len then Str = Str..(" "):rep(Cur-len) end | |
if O.condition then return O.condition(Str,Cur,AKEY) end | |
return true | |
end | |
local function forward(skip) | |
Pos = search(Str,Cur,skip,1) | |
return Pos and O.prio | |
end | |
local function backward(skip) | |
Pos = search(Str:reverse(),Str:len()-Cur+1,skip,2) | |
if Pos then | |
Pos = Str:len()-Pos+1 | |
return O.prio | |
end | |
end | |
Macro { description="Word right (smooth)"; | |
area=O.areas; key=O.side.."CtrlRight"; | |
id="CCD1022F-B2C2-45FB-BC8E-D4E7613C385E"; | |
condition=function(AKEY) | |
return getInfo() and forward(AKEY) | |
end; | |
action=function() | |
setPos(Pos) | |
end; | |
} | |
Macro { description="Select block right (smooth)"; | |
area=O.areas; key=O.side.."CtrlShiftRight"; | |
id="BE4CBE4E-8D0A-43B0-973E-451891627199"; | |
condition=function(AKEY) | |
return getInfo() and forward(AKEY) | |
end; | |
action=function() | |
local keys = "ShiftRight" | |
if not Area.Editor and not Area.Dialog then | |
keys = "Alt"..keys | |
end | |
Keys((Pos-Cur).."*"..keys) | |
end; | |
} | |
Macro { description="Delete word right (smooth)"; | |
area=O.areas; key=O.side.."CtrlDel "..O.side.."CtrlT"; | |
id="765BB924-189E-4A4E-943E-8AB02A7CCDF1"; | |
condition=function(AKEY) | |
return getInfo(AKEY) and forward(AKEY) | |
end; | |
action=function() | |
Str = Str:sub(1,Cur-1)..Str:sub(Pos,-1) | |
setStr(Str) | |
setPos(Cur) | |
end; | |
} | |
Macro { description="Word left (smooth)"; | |
area=O.areas; key=O.side.."CtrlLeft"; | |
id="35C87D22-79A6-42EA-8168-0F6035ABC68B"; | |
condition=function(AKEY) | |
return getInfo() and backward(AKEY) | |
end; | |
action=function() | |
setPos(Pos) | |
end; | |
} | |
Macro { description="Select block left (smooth)"; | |
area=O.areas; key=O.side.."CtrlShiftLeft"; | |
id="2F1717A9-9257-49DE-9837-4FAA96F3DFB8"; | |
condition=function(AKEY) | |
return getInfo() and backward(AKEY) | |
end; | |
action=function() | |
local keys = "ShiftLeft" | |
if not Area.Editor and not Area.Dialog then | |
keys = "Alt"..keys | |
end | |
Keys((Cur-Pos).."*"..keys) | |
end; | |
} | |
Macro { description="Delete word left (smooth)"; | |
area=O.areas; key=O.side.."CtrlBS"; | |
id="0CB736DA-861F-43AC-81C4-C112D277B4B2"; | |
condition=function(AKEY) | |
return getInfo() and backward(AKEY) | |
end; | |
action=function() | |
Str = Str:sub(1,Pos-1)..Str:sub(Cur,-1) | |
setStr(Str) | |
setPos(Pos) | |
end; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
pagetitle: SmoothMove | |
--- | |
**SmoothMove** — переход по словам с дополнительными остановками на _camel**C**ase_ и _snake\_**c**ase_ | |
============== | |
Предлагаю набор макросов по мотивам плагина [Smooth move](https://plugring.farmanager.com/plugin.php?pid=235). | |
Работает в редакторе, в диалогах, и в командной строке. Вносит изменение в работу следующих функций: | |
- перемещение по словам: `Ctrl+Left/Right` | |
- выделение по словам: `Ctrl+Shift+Left/Right` | |
- удаление по словам: `Ctrl+BS/Del/T` | |
(комбинации `Num4/6` не используются) | |
В начале скрипта есть таблица с опциями, которые можно изменять редактируя файл, | |
или используя возможности **cfgscript*** | |
`areas` (string) | |
: Определяет макрообласти, в которых работают данные макросы. | |
По умолчанию: `"Editor Dialog Shell QView Info Tree"`. | |
`side` (string) | |
: Даёт возможность переопределить клавиши, на которые назначены макросы. | |
По умолчанию: `""`, т.е. макросы работают как с лево- так и с правосторонними модификаторами. | |
Можно ограничить одной стороной, указав `"R"` или `"L"`. | |
`prio` (number) | |
: Определяет приоритет макросов. | |
По умолчанию: `40`, чтобы уменьшить вероятность конфликта с другими пользовательскими макросами. | |
`word` (string) | |
: Определяет паттерн для поиска слова. | |
По умолчанию: `"[%w_]"`. | |
`stops` (table) | |
: Таблица со списком паттернов для поиска остановок внутри слова. Содержит пары _{прямой, обратный}_. | |
По умолчанию: заданы паттерны для _camel**C**ase_ и _snake\_**c**ase_. | |
В комментариях приведён пример альтернативного паттерна для _snake**\_**case_, | |
при котором остановки будут не на первой букве слова, а на символе подчёркивания. | |
`findWord` (function) | |
: Пользовательская функция для поиска слова. | |
В исходном коде приведён пример функции, при которой макросы срабатывают только если курсор уже находится внутри слова. | |
`condition` (function) | |
: Пользовательская функция, устанавливающая дополнительное ограничение для срабатывания макросов. | |
В исходном коде приведён пример функции, при которой макросы работают только если включен ScrollLock. | |
- - - | |
[*] Чтобы после каждого обновления скрипта не приходилось вручную восстанавливать | |
изменённые значения опций рекомендуется использовать возможности **cfgscript** из пакета | |
**ScriptsBrowser**: <http://forum.farmanager.com/viewtopic.php?f=15&t=10418> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment