--[[ Editor macros ]]--
----------------------------------------
--[[ description:
-- Macros for editor area.
-- Макросы для области редактора.
--]]
----------------------------------------
--[[ uses:
nil.
-- group: Macros/Manager.
--]]
--------------------------------------------------------------------------------
local tonumber, tostring = tonumber, tostring
----------------------------------------
local far = far
local F = far.Flags
local BlockNoneType = F.BTYPE_NONE
local editor = editor
----------------------------------------
--local context = context
local numbers = require 'context.utils.useNumbers'
local strings = require 'context.utils.useStrings'
----------------------------------------
--[[
local dbg = require "context.utils.useDebugs"
local logShow = dbg.Show
--]]
--------------------------------------------------------------------------------
local unit = {}
----------------------------------------
--local guids = {}
--unit.guids = guids
local Macro = Macro or function () end
---------------------------------------- Testing
--[[
Macro {
area = "Editor",
key = "CtrlQ",
flags = "",
description = "Edit: Test",
action = function ()
prints("test")
return prints("abc", 10, "def")
end, ---
} ---
--]]
---------------------------------------- Actions
-- [[
Macro {
area = "Editor",
key = "AltF9",
flags = "",
description = "Edit: Next codepage",
action = function ()
Keys"ShiftF8"
if not Area.Menu then return end
--far.Message(("%#08x"):format(Menu.ItemStatus()))
repeat
Keys"Down"
until band(Menu.ItemStatus(), 0x0000003C) == 0
return Keys"Enter"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftG",
flags = "",
description = "Edit: Goto…",
action = function () return Keys"AltF8" end, ---
} ---
--]]
---------------------------------------- File
-- [[
Macro {
area = "Editor",
key = "CtrlAltShiftL",
flags = "",
description = "Edit: Lock/Unlock",
action = function () return Keys"CtrlL" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltShiftEnter",
flags = "",
description = "Edit: Insert full filename",
action = function () return Keys"CtrlF" end, ---
} ---
--]]
--[[
Macro {
area = "Editor",
key = "CtrlO",
flags = "",
description = "Edit: Switch to panels",
action = function () return Keys"F12 0" end, ---
} ---
--]]
-- [[
Macro {
area = "Editor",
key = "CtrlS",
flags = "",
description = "Edit: Save file",
action = function ()
local IsExist = mf.fexist(Editor.FileName)
--far.Message(tostring(mIsExist), Editor.FileName)
Keys"F2" -- Сохранение
if IsExist and Area.Dialog then
return Keys"Enter" -- Подтверждение сохранения для ReadOnly-файла
end
end, ---
} ---
--]]
-- Save file with codepage UTF-8 without BOM.
-- Сохранение файла в кодировке UTF-8 без BOM.
function unit.SaveAsUtf8noBOM (Ask)
--local isOk = true -- DEBUG only
if Ask then
local isOk = far.Message("Save this file as UTF-8?",
"Warning!", ";YesNo", "w") == 1
--far.Message(isOk, "SaveAsUtf8noBOM")
if not isOk then return end -- Отмена --> Не сохранять
end
--far.Message(tostring(check), Editor.FileName)
local Info = editor.GetInfo() -- Сохранение текущих линии и позиции
Keys"ShiftF2" -- Сохранение
Keys"Tab" -- Переключение на выбор кодовой страницы
local id = Dlg.CurPos
Keys"CtrlDown" -- Раскрытие списка
-- Поиск в списке
local sfind = string.find
local value = Dlg.GetValue(id, 0) or "" -- Значение
--far.Message(value, Dlg.GetValue(id, 7))
if not sfind(value, "65001", 1, true) then
-- Переход на самый верхний элемент списка
local start = Dlg.GetValue(id, 7)
while Dlg.GetValue(id, 7) <= start do Keys"Up" end
Keys"Down"
-- Поиск по всем элементам списка
value = Dlg.GetValue(id, 0) or ""
start = Dlg.GetValue(id, 7) - 1
while Dlg.GetValue(id, 7) > start and
not sfind(value, "65001", 1, true) do
Keys"Down"
value = Dlg.GetValue(id, 0) or ""
end
-- Элемент не найден --> Отмена
if not sfind(value, "65001", 1, true) then
return Keys"Esc Esc" -- Отмена списка и окна сохранения
end
end
Keys"Enter" -- Закрытие списка с выбором элемента
Keys"Tab Subtract" -- Отмена выбора сигнатуры (BOM)
Keys"Enter" -- Закрытие окна сохранения с подтверждением
-- Закрытие подтверждающих окон:
if Area.Dialog then Keys"Enter" end
if Area.Dialog then Keys"Enter" end
-- Восстановление текущих линии и позиции
return editor.SetPosition(Info.EditorID, Info.CurLine, Info.CurPos)
end ---- SaveAsUtf8noBOM
-- [[
Macro {
area = "Editor",
key = "CtrlShiftS",
flags = "",
description = "Edit: Save as UTF-8 w/o BOM",
action = function ()
return unit.SaveAsUtf8noBOM(true)
end, ---
} ---
--]]
---------------------------------------- Search
-- [[
Macro {
area = "Editor",
key = "CtrlF",
flags = "",
description = "Edit: Find…",
action = function () return Keys"F7" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlR",
flags = "",
description = "Edit: Replace…",
action = function () return Keys"CtrlF7" end, ---
} ---
Macro {
area = "Editor",
key = "F3",
flags = "",
description = "Edit: Find next",
action = function () return Keys"ShiftF7" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlF3",
flags = "",
description = "Edit: Find next & center",
action = function ()
Keys"ShiftF7"
if Area.Dialog then return end -- Не найдено
local Info = editor.GetInfo()
if not Info then return end
local shift = Info.CurPos - Info.WindowSizeX / 4 * 3
if shift > 0 then
return editor.SetPosition(Info.EditorID, -1, Info.LeftPos + shift)
end
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltShiftF7",
flags = "",
description = "Edit: Replace all",
action = function ()
Keys"CtrlF7 Enter" -- Замена первого вхождения
if Area.Dialog then
return Keys"Right Enter" -- Замена остальных вхождений
end
end, ---
} ---
--]]
---------------------------------------- Space
-- [[
Macro {
area = "Editor",
key = "AltBS",
flags = "",
description = "Edit: Tabulation",
action = function () return Keys"Tab" end, ---
} ---
Macro {
area = "Editor",
key = "ShiftBS",
flags = "",
description = "Edit: Double space",
action = function () return Keys"Space Space" end, ---
} ---
Macro {
area = "Editor",
key = "Tab",
flags = "",
description = "Edit: Spaced tab / Indent",
action = function ()
local Info = editor.GetInfo()
if Info.BlockType == BlockNoneType then
local Pos = Info.CurPos
Pos = 4 - (Pos - 1) % 4
--far.Message(Pos, Info.CurPos)
for k = 1, Pos do Keys"Space" end
else
return Keys"AltI" -- Сдвиг выделения вправо
end
end, ---
} ---
Macro {
area = "Editor",
key = "ShiftTab",
flags = "",
description = "Edit: Spaced half-tab / Unindent",
action = function ()
local Info = editor.GetInfo()
if Info.BlockType == BlockNoneType then
local Pos = Info.CurPos
Pos = 2 - (Pos - 1) % 2
--far.Message(Pos, Info.CurPos)
for k = 1, Pos do Keys"Space" end
else
return Keys"AltU" -- Сдвиг выделения влево
end
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltShiftTab",
flags = "",
description = "Edit: Table-Tab",
condition = function ()
local Info = editor.GetInfo()
return Info.BlockType == BlockNoneType
end, ---
action = function ()
Keys"Tab Left" -- Табуляция с сохранением позиции
local Info = editor.GetInfo()
if Info.CurLine < Info.TotalLines then
return Keys"Down" -- Перемещение на следующую строку
end
end, ---
} ---
--]]
---------------------------------------- Move text
-- [[
Macro {
area = "Editor",
key = "Left",
flags = "",
description = "Edit: Left within line",
action = function () return Keys"CtrlS" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlD",
flags = "",
description = "Edit: Left within file",
action = function () return Keys"Left" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftD",
flags = "",
description = "Edit: Right within file",
action = function ()
local Info = editor.GetInfo()
local s = editor.GetString(Info.EditorID, 0, 2)
if Info.CurPos > s:len() then
return Keys"Down Home"
else
return Keys"Right"
end
end, ---
} ---
Macro {
area = "Editor",
key = "Num4",
flags = "",
description = "Edit: Left within line",
action = function () return Keys"CtrlS" end, ---
} ---
Macro {
area = "Editor",
key = "Num6",
flags = "",
description = "Edit: Right within line",
action = function () return Keys"Right" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltHome",
flags = "",
description = "Edit: Start of first line",
action = function () return Keys"CtrlHome Home" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltEnd",
flags = "",
description = "Edit: Start of last line",
action = function () return Keys"CtrlEnd Home" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlNum1",
flags = "",
description = "Edit: End of last line",
action = function () return Keys"CtrlEnd End" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlNum7",
flags = "",
description = "Edit: Start of first line",
action = function () return Keys"CtrlHome Home" end, ---
} ---
--]]
---------------------------------------- Move block
--[[
Macro {
area = "Editor",
key = "CtrlShiftI",
flags = "",
description = "Edit: Shift 4fold block right",
action = function () return Keys"AltI AltI AltI AltI" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftU",
flags = "",
description = "Edit: Shift 4fold block left",
action = function () return Keys"AltU AltU AltU AltU" end, ---
} ---
Macro {
area = "Editor",
key = "AltShiftI",
flags = "",
description = "Edit: Shift twice block right",
action = function () return Keys"AltI AltI" end, ---
} ---
Macro {
area = "Editor",
key = "AltShiftU",
flags = "",
description = "Edit: Shift twice block left",
action = function () return Keys"AltU AltU" end, ---
} ---
--]]
---------------------------------------- Position
-- Shift a current line from screen top/bottom.
-- Смещение текущей линии относительно верха/низа экрана.
function unit.ShiftCurLine (Shift)
local Info = editor.GetInfo()
local Line = Info.CurLine
if Shift > 0 then
Line = math.max(Line - Shift, 1)
else
Line = math.max(Line - (Info.WindowSizeY + Shift), 1)
end
return editor.SetPosition(Info.EditorID, { TopScreenLine = Line })
end ---- ShiftCurLine
-- [[
Macro {
area = "Editor",
key = "CtrlEnter",
flags = "",
description = "Edit: Shift up current line",
action = function () return unit.ShiftCurLine(7) end, ---
} ---
Macro {
area = "Editor",
key = "CtrlNumEnter",
flags = "",
description = "Edit: Shift up current line",
action = function () return unit.ShiftCurLine(7) end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltEnter",
flags = "",
description = "Edit: Shift down current line",
action = function () return unit.ShiftCurLine(-4) end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltNumEnter",
flags = "",
description = "Edit: Shift down current line",
action = function () return unit.ShiftCurLine(-4) end, ---
} ---
--]]
---------------------------------------- Clipboard
-- [[
Macro {
area = "Editor",
key = "CtrlC",
flags = "",
description = "Edit: Copy selection only",
action = function ()
local Info = editor.GetInfo()
if Info.BlockType ~= BlockNoneType then
return Keys"CtrlC"
end
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlIns",
flags = "",
description = "Edit: Copy selection only",
action = function ()
local Info = editor.GetInfo()
if Info.BlockType ~= BlockNoneType then
return Keys"CtrlIns"
end
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftIns",
flags = "",
description = "Edit: Add to clipboard",
action = function ()
local Info = editor.GetInfo()
if Info.BlockType ~= BlockNoneType then
return Keys"CtrlAdd"
end
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltV",
flags = "",
description = "Edit: Paste + Down",
action = function () return Keys"CtrlV Down" end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftV",
flags = "",
description = "Edit: Paste + Down + End",
action = function () return Keys"CtrlV Down End" end, ---
} ---
--]]
---------------------------------------- Numeration
do
local isdigit = strings.isdigit
-- Find a number position.
-- Поиск положения числа.
--[[
-- @params:
Info (table) - info about editor state.
Line (number) - line number (@default = current line).
Pos (number) - position number (@default = current position).
-- @return:
s (nil|string) - line content.
PosB (number) - number begin position.
PosE (number) - number end position.
--]]
function unit.FindNumberPos (Info, Line, Pos)
local Info = Info or editor.GetInfo()
local s = editor.GetString(Info.EditorID, Line or 0, 2)
--far.Message(s, s:len())
if not s then return end
local Len = s:len()
if Len == 0 then return end
local Pos = Pos or Info.CurPos
if Pos <= 0 then
Pos = Len + Pos + 1
end
local PosB, PosE -- begin/end pos
local atEnd = Len < Pos
if atEnd then PosE = Len end
local f = isdigit(s:sub(Pos, Pos))
--far.Message(f, Pos)
if not f then
if atEnd or Pos < 2 then return end
Pos = Pos - 1
PosE = Pos
f = isdigit(s:sub(Pos, Pos))
if not f then return end
end
local k = Pos
while k > 0 and isdigit(s:sub(k, k)) do
k = k - 1
end
PosB = k + 1
if not PosE then
local k = Pos
while k <= Len and isdigit(s:sub(k, k)) do
k = k + 1
end
PosE = k - 1
end
if not PosB and not PosE or PosE < PosB then return end
--[[
local t = {
tostring(PosB),
tostring(PosE),
'"'..s:sub(PosB, PosE)..'"',
} ---
far.Message(table.concat(t, "\n"), "FindNumberPos")
--]]
return s, PosB, PosE
end ---- FindNumberPos
-- Find a string with number
-- on specified position of lines above/below specified line.
-- Поиск строки с числом
-- на указанной позиции линий выше/ниже указанной линии.
--[[
-- @params:
Info (table) - info about editor state.
Line (number) - line number (@default = current line).
Pos (number) - position number (@default = current position).
Shift (number) - direction toward specified line.
Limit (number) - count of searched lines.
-- @return:
s (nil|string) - line content.
PosB (number) - number begin position.
PosE (number) - number end position.
--]]
function unit.FindNumberStr (Info, Line, Pos, Shift, Limit)
local Info = Info or editor.GetInfo()
local Pos = Pos or Info.CurPos
local Line = Line or Info.CurLine
local Count = Info.TotalLines
local Shift, Limit = Shift or -1, Limit or Count
local abs, FindNumberPos = math.abs, unit.FindNumberPos
-- Просмотр строк выше/ниже:
local s, PosB, PosE
local k = Line
while not s and
abs(k - Line) <= Limit and
(k >= 0 and k < Count) do
k = k + Shift
s, PosB, PosE = FindNumberPos(Info, k, Pos)
--[[
if s then
local t = {
tostring(PosB),
tostring(PosE),
'"'..(s and s:sub(PosB, PosE) or "")..'"',
'"'..(s or "")..'"',
} ---
far.Message(table.concat(t, "\n"), "FindNumberStr")
end
--]]
end
--[[
local t = {
tostring(k),
tostring(PosB),
tostring(PosE),
s,
'"'..(s and s:sub(PosB, PosE) or "")..'"',
} ---
far.Message(table.concat(t, "\n"), "FindNumberStr")
--]]
editor.SetPosition(Info.EditorID, Info)
if not s then return end
return s:sub(PosB, PosE)
end ---- FindNumberStr
end -- do
do
local isdigit = strings.isdigit
local digit, todigit = strings.digit, strings.todigit
-- Shift a digit value on current position of current line.
-- Смещение значения цифры на текущей позиции текущей линии.
function unit.ShiftDigit (Shift)
local Info = editor.GetInfo()
local s = editor.GetString(Info.EditorID, 0, 2)
--far.Message(s:len(), Pos)
if not s then return end
local Len = s:len()
if Len == 0 then return end
local Pos = Info.CurPos
local atEnd = Len < Pos
if atEnd then Pos = Len end
local c = todigit(s:sub(Pos, Pos))
--far.Message(c, Pos)
if c < 0 then
if atEnd or Pos < 2 then return end
Pos = Pos - 1
c = todigit(s:sub(Pos, Pos))
if c < 0 then return end
end
c = digit((c + Shift) % 10)
s = s:sub(1, Pos - 1)..c..s:sub(Pos + 1, -1)
return editor.SetString(Info.EditorID, 0, s)
end ---- ShiftDigit
local ssub, srep = string.sub, string.rep
-- Shift a number value on current position of current line.
-- Смещение значения числа на текущей позиции текущей линии.
function unit.ShiftNumber (Shift)
local Info = editor.GetInfo()
local s, PosB, PosE = unit.FindNumberPos(Info, 0, Info.CurPos)
if not s then return end
local c = s:sub(PosB, PosE)
local n = tonumber(c)
if not n then return end
--far.Message(n, Shift)
n = n + Shift
local Len = c:len()
if n >= 0 then
c = ssub(srep("0", Len)..tostring(n), -Len, -1)
else
c = srep("9", Len)
end
s = s:sub(1, PosB - 1)..c..s:sub(PosE + 1, -1)
return editor.SetString(Info.EditorID, 0, s)
end ---- ShiftNumber
end -- do
-- [[
Macro {
area = "Editor",
key = "AltLeft",
flags = "",
description = "Edit: Digit decrement",
action = function () return unit.ShiftDigit(-1) end, ---
} ---
Macro {
area = "Editor",
key = "AltRight",
flags = "",
description = "Edit: Digit increment",
action = function () return unit.ShiftDigit(1) end, ---
} ---
--]]
Macro {
area = "Editor",
key = "AltDown",
flags = "",
description = "Edit: Number decrement",
action = function () return unit.ShiftNumber(-1) end, ---
} ---
Macro {
area = "Editor",
key = "AltUp",
flags = "",
description = "Edit: Number increment",
action = function () return unit.ShiftNumber(1) end, ---
} ---
do
local srep, format = string.rep, string.format
-- Make a number value with separators.
-- Формирование значения числа с разделителями.
--[[
-- @params:
s (string) - a string with number.
sep (string) - a separator value.
group (number) - a number of digits to separate as group.
limit (number) - a maximum number of digits to separate never.
--]]
function unit.toseparate (s, sep, group, limit)
if not s then return end
local len = s:len()
local group = group or 3
if len <= group then return end
if limit and len <= limit then return end
--far.Message(reverse(c), Separator)
local sep = sep or " "
s = s:reverse():gsub(srep(".", group), "%0"..sep)
return s:reverse():gsub(format("^[%s]+", sep), "")
end ---- toseparate
-- Insert separator to number value.
-- Вставка разделителя в значение числа.
--[[
-- @params:
Separator (string) - a separator value.
GroupSize (number) - a number of digits to separate as group.
MaxDigits (number) - a maximum number of digits to separate never.
--]]
function unit.SeparateNumber (Separator, GroupSize, MaxDigits)
local Info = editor.GetInfo()
local s, PosB, PosE = unit.FindNumberPos(Info, 0, Info.CurPos)
if not s then return end
local c = s:sub(PosB, PosE)
if not c then return end
c = unit.toseparate(c, Separator, GroupSize, MaxDigits)
if not c then return end
s = s:sub(1, PosB - 1)..c..s:sub(PosE + 1, -1)
return editor.SetString(Info.EditorID, 0, s)
end ---- SeparateNumber
end -- do
do
local format = string.format
local round = numbers.round
local ByteFold = 1024
local BytePrefixes = {
{ name = "B", fold = 1, },
{ name = "KiB", fold = ByteFold, },
{ name = "MiB", fold = ByteFold*ByteFold, },
{ name = "GiB", fold = ByteFold*ByteFold*ByteFold, },
{ name = "TiB", fold = ByteFold*ByteFold*ByteFold*ByteFold, },
} --- BytePrefixes
-- Make a size value with prefixes.
-- Формирование значения размера с использованием префиксов.
--[[
-- @params:
v (string|number) - a size value.
-- @return:
value (string) - size using prefix.
prefix (string) - prefix name.
--]]
function unit.tobytefold (v)
if not v then return end
local n = v
if type(n) == 'string' then n = tonumber(n) end
if not n then return end
local Prefixes = BytePrefixes
local k, count = 1, #Prefixes
while k <= count and Prefixes[k].fold <= n do k = k + 1 end
k = k - 1
local Prefix = Prefixes[k]
if k == 1 then return end
--if k == 1 then return 1, Prefix.name end
n = n / Prefix.fold
if n < 10 then
n = format("%.2f", round(n * 100) / 100)
elseif n < 100 then
n = format("%.1f", round(n * 10) / 10)
else
n = format("%.0f", round(n))
end
--far.Message(n, Prefix.name)
return n and n:gsub("%.", ","), Prefix.name
end ---- tobytefold
local FoldByteFmt = "%s %s (%s B)"
-- Make a size value as a byte measure.
-- Формирование значения размера как размерности в байтах.
--[[
-- @params: @see unit.SeparateNumber.
--]]
function unit.FoldByteSize (Separator, GroupSize, MaxDigits)
local Info = editor.GetInfo()
local s, PosB, PosE = unit.FindNumberPos(Info, 0, Info.CurPos)
if not s then return end
local c = s:sub(PosB, PosE)
if not c then return end
-- Size in bytes with separators.
local b = unit.toseparate(c, Separator, GroupSize, MaxDigits) or c
--if not b then return end
-- Size in bytefolds.
local f, n = unit.tobytefold(c)
if not f then return end
c = FoldByteFmt:format(f, n, b)
s = s:sub(1, PosB - 1)..c..s:sub(PosE + 1, -1)
editor.SetString(Info.EditorID, 0, s)
return editor.SetPosition(Info.EditorID, 0, PosB + c:len() - 1)
end ---- FoldByteSize
end -- do
-- [[
Macro {
area = "Editor",
key = "AltQ",
flags = "",
description = "Edit: Number spacing",
action = function ()
return unit.SeparateNumber(" ", 3, 4)
end, ---
} ---
Macro {
area = "Editor",
key = "AltShiftQ",
flags = "",
description = "Edit: Bytes folding",
action = function ()
return unit.FoldByteSize(" ", 3, 4)
end, ---
} ---
--]]
---------------------------------------- Readme
---------------------------------------- -- Page number
-- [[
Macro {
area = "Editor",
key = "AltP",
flags = "",
description = "ReadMe: Text (|)",
action = function ()
Keys"End"
print" ()"
Keys"Left"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltP",
flags = "",
description = "ReadMe: Text (|) Text",
action = function ()
print" ()"
Keys"Left"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlP",
flags = "",
description = "ReadMe: (Text)|",
action = function ()
print"("
Keys"End"
print")"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftP",
flags = "",
description = "ReadMe: (Text)| + Next",
action = function ()
print"("
Keys"End"
print")"
Keys"Down End CtrlLeft"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltShiftP",
flags = "",
description = "ReadMe: (Number)| + Next",
action = function ()
print"("
Keys"End"
print")"
Keys"Down End"
-- TODO: Доделать: выделять только числа, текст пропускать?!
Keys"CtrlLeft"
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlO",
flags = "",
description = "ReadMe: (|Number)",
action = function ()
Keys"End"
print")"
Keys"CtrlLeft"
print"("
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlAltShiftO",
flags = "",
description = "ReadMe: (Num / Num)| + Next",
action = function ()
Keys"End"
print")"
Keys"CtrlLeft CtrlLeft CtrlLeft"
print"("
Keys"Down End"
end, ---
} ---
-- Autoset a previous page number.
-- Автоустановка предыдущего номера страницы.
Macro {
area = "Editor",
key = "AltShiftZ",
flags = "",
description = "ReadMe: (Num) from up",
action = function ()
Keys"End"
local Info = editor.GetInfo()
-- Поиск с предпоследней позиции, так исключается ")"!
local n = unit.FindNumberStr(Info, Info.CurLine, -2, -1, 100)
print" ()"
Keys"Left"
if n then
print(n)
end
end, ---
} ---
--]]
---------------------------------------- -- List bullet
-- [[
do
local BulletSep = ". "
local Bullets = {
["#"] = { level = "Num", key = "Alt1", },
["*"] = { level = "1", key = "AltShift1", },
["-"] = { level = "2", key = "Alt2", },
[":"] = { level = "Lib", key = "AltShift2", },
["~"] = { level = "3", key = "Alt3", },
["·"] = { level = "4", key = "AltShift3", },
} --- Bullets
local DescFmt = "Bullet: '%s%s' (Level %s)"
for k, v in pairs(Bullets) do
if k ~= "" then
Macro {
area = "Editor",
key = v.key,
flags = "",
description = DescFmt:format(k, BulletSep, v.level),
action = function ()
print(k..BulletSep)
--prints(k, BulletSep)
end, ---
} ---
end
end
--[=[
-- WARN: Закомментировано, т.к. занято на Quote-макросы.
local IndentBullets = {
["-"] = { level = "2", key = "CtrlAltShift1", },
[" ~"] = { level = "3", key = "CtrlAltShift2", },
[" ·"] = { level = "4", key = "CtrlAltShift3", },
} --- IndentBullets
local DescFmt = "Bullet: '%s%s' (L%s) + Next"
for k, v in pairs(IndentBullets) do
if k ~= "" then
Macro {
area = "Editor",
key = v.key,
flags = "",
description = DescFmt:format(k, BulletSep, v.level),
action = function ()
local Info = editor.GetInfo()
print(k..BulletSep)
return editor.SetPosition(Info.EditorID,
Info.CurLine + 1, Info.CurPos)
end, ---
} ---
end
end
--]=]
end -- do
--]]
---------------------------------------- -- Section number
-- [[
-- Autoset a section number (incremently).
-- Автоустановка номера раздела (с инкрементом).
local function AutoSectionNumber ()
local Info = editor.GetInfo()
local s = unit.FindNumberStr(Info, Info.CurLine, Info.CurPos, -1, 100)
-- TODO: Переделать с использованием только Lua, без Keys/print.
if s then
local sLen = s:len()
local n = tostring(tonumber(s) + 1)
local nLen = n:len()
--far.Message('"'..s..'"\n"'..n..'"\n')
if nLen > sLen then
Keys"CtrlS"
elseif nLen < sLen then
print("0")
end
return print(n..". ")
else
return print("1. ")
end
end ---- AutoSectionNumber
local SectionPat = "[^%.]*%."
-- Clear a section number from all supersections' numbers.
-- Очистка номера раздела от всех номеров надразделов.
--[[
-- @params:
Level (number) - a number of sections to clear (@default = all but last).
Subst (string) - a substitution of section number (@default = two spaces).
Kind (string) - a kind of section numeration (@default: "both"):
"number", "roman", "both", "all".
--]]
local function ClearSectionNumber (Level, Subst, Kind)
local Info = editor.GetInfo()
local id = Info.EditorID
-- Пропуск пустых строк:
local s -- Текущая линия
local Line = Info.CurLine
repeat
if Line == Info.TotalLines then return end
s = editor.GetString(id, 0, 2)
-- Следующая линия:
Line = Line + 1
editor.SetPosition(id, Line)
until not s:find("^%s-$")
local PosB, PosE = s:cfind("[^%s]+") -- Позиция начала и конца
if not PosB then return end
--far.Message(PosE, PosB)
-- Подстрока с номерами:
local c = s:sub(PosB, PosE)
if c == s then return end -- Только текст
--far.Message(c, c:len())
if c:sub(-1, -1) ~= "." then c = c.."." end
local _, Count = c:gsub(SectionPat, "") -- Количество номеров
--far.Message(c, Count)
local Level = Level or Count - 1
local Subst = Subst or " "
local Kind = Kind or "both"
Count = Level
local function ReplaceSection (s)
if s == "." then return "" end
if Kind == "all" then return Subst end
if Kind == "number" then
if s:find("^%d+%.$") then return Subst end
elseif Kind == "roman" then
if s:find("^[IVXLCDMivxlcdm]+%.$") then return Subst end
elseif Kind == "both" then
if s:find("^[%dIVXLCDMivxlcdm]+%.$") then return Subst end
end
Count = Count - 1 -- Без замены
end -- ReplaceSection
c, Count = c:gsub(SectionPat, ReplaceSection, Level)
--far.Message('"'..c..'"', tostring(Level - Count > 0))
--far.Message('"'..c..'"', tostring(Level).." - "..tostring(Count))
--[[
local t = {
tostring(PosB),
tostring(PosE),
'"'..c..'"',
'"'..s..'"',
} ---
far.Message(table.concat(t, "\n"), Line)
--]]
if Count > 0 and Count == Level then
s = s:sub(1, PosB - 1)..c..s:sub(PosE + 1, -1)
--far.Message('"'..s..'"', c:len())
editor.SetPosition(id, Line - 1) -- Текущая линия
editor.SetString(id, 0, s) -- Обновление линии
return editor.SetPosition(id, Line) -- Следующая линия
end
end -- ClearSectionNumber
Macro {
area = "Editor",
key = "AltZ",
flags = "",
description = "ReadMe: 'Num. ' from up",
action = function ()
return AutoSectionNumber()
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlY",
flags = "",
description = "ReadMe: Clear first 'Num. '",
action = function ()
return ClearSectionNumber(1, nil, "both")
end, ---
} ---
Macro {
area = "Editor",
key = "CtrlShiftY",
flags = "",
description = "ReadMe: Clear all 'Num. ' but last",
action = function ()
return ClearSectionNumber(nil, nil, "both")
end, ---
} ---
--]]
---------------------------------------- Characters
-- [[
do
local BSh = "BackSlash"
local Characters = {
-- Alt + -- -- Alt + Shift + --
-- Latin key-characters: -- Latin number-characters:
["["] = "Alt[", ["{"] = "AltShift[",
["]"] = "Alt]", ["}"] = "AltShift]",
[","] = "Alt,", ["<"] = "AltShift,", ["#"] = "CtrlAltShift,",
["."] = "Alt.", [">"] = "AltShift.", ["^"] = "CtrlAltShift.",
[";"] = "Alt;", [":"] = "AltShift;", ["$"] = "CtrlAltShift;",
["'"] = "Alt'", ['"'] = "AltShift'", ["@"] = "CtrlAltShift'",
["`"] = "Alt`", ["~"] = "AltShift`",
["/"] = "Alt/", ["?"] = "AltShift/", ["&"] = "CtrlAltShift/",
["\\"] = "Alt"..BSh, ["|"] = "AltShift"..BSh, ["‾"] = "CtrlAltShift"..BSh,
-- Special characters:
[" "] = "CtrlShiftSpace",
["…"] = "CtrlAlt/",
["°"] = "Shift"..BSh,
["́"] = "Ctrl"..BSh,
["§"] = "CtrlShift"..BSh,
["―"] = "CtrlAlt"..BSh,
["≤"] = "CtrlAlt,",
["≥"] = "CtrlAlt.",
-- Math/Lang characters with Numpad:
-- Num+ — Add -- -- Num* — Multiply --
["−"] = "ShiftAdd", ["⋅"] = "ShiftMultiply",
["±"] = "CtrlAdd", ["×"] = "CtrlMultiply",
["∓"] = "CtrlShiftAdd", ["¤"] = "CtrlShiftMultiply",
[" "] = "CtrlAltAdd", ["·"] = "CtrlAltMultiply",
["∑"] = "AltAdd", ["∏"] = "AltMultiply",
["∫"] = "AltShiftAdd", ["∂"] = "AltShiftMultiply",
-- Num- — Subtract -- -- Num/ — Divide --
[""] = "ShiftSubtract", ["÷"] = "ShiftDivide",
["—"] = "CtrlSubtract", ["∕"] = "CtrlDivide",
["‑"] = "CtrlShiftSubtract", ["∞"] = "CtrlShiftDivide",
["–"] = "CtrlAltSubtract", ["⁄"] = "CtrlAltDivide",
[" "] = "AltSubtract", ["√"] = "AltDivide",
["‒"] = "AltShiftSubtract", ["∛"] = "AltShiftDivide",
-- Graphic characters with Numpad:
["┼"] = "CtrlAltShiftAdd", ["●"] = "CtrlAltShiftMultiply",
["─"] = "CtrlAltShiftSubtract", ["│"] = "CtrlAltShiftDivide",
} --- Characters
----------------------------------------
local u8byte = strings.u8byte -- UTF-8 char to codepoint
local ucp2s = strings.ucp2s -- Char codepoint to string
local DescFmt = "Char: '%s' | U-%s"
for k, v in pairs(Characters) do
if k ~= "" then
Macro {
area = "Editor",
key = v,
flags = "",
description = DescFmt:format(k, ucp2s(u8byte(k), true)),
action = function () print(k) end, ---
} ---
end
end
end -- do
--]]
--------------------------------------------------------------------------------