Skip to content

Instantly share code, notes, and snippets.

@johnd0e
Last active April 16, 2023 16:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnd0e/d79b55ce7fed21b921028a0dea49ed91 to your computer and use it in GitHub Desktop.
Save johnd0e/d79b55ce7fed21b921028a0dea49ed91 to your computer and use it in GitHub Desktop.
SmoothMove
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;
}
---
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