Re: SciTE customisation with Lua Scripts
andrew strain <[email protected]> Wed, 31 Jan 2024 18:24:36 -0800 (PST)
| Newsgroups | gmane.editors.scite.general |
|---|---|
| Message-ID | <[email protected]> |
Hi - I'm assuming this bumped topic as the latest centralised resource to share lua scripts ;) So here are three refined features yanked out of my sprawling collection (codeberg.org/lusci/lusci) to work under Gavin's neat set up. There is also a GetClipboard() function with no dependencies at the top that is not used within but might be handy. The three main functions are: keypr_sort() - toggles standard and natural sort order in selected text keypr_twiddle() - reverses selected words or lines or column, or flips letters at caret keypr_cyclecase() - cycles through lower > Sentence > First Letter > ALL CAPS of selected They are made to work with normal or monospaced rectangular selections. I put twiddle and sort on ctrl+t and shift+ctrl+t and cyclecase on ctrl+u It occurs to me momentarily, the sort would be better if it included a shuffle phase... ...a future version. Best wishes - andrew On Sunday 21 January 2024 at 18:19:11 UTC Gavin Holt wrote: > Hi, > > Answering your questions: > > *extensions.lua* - is a lua script I use for many lua projects. It adds > functions to the standard libraries which are missing. The necessary > functions are now in SciTE.lua. > > *extman.lua *- was a way of combining different plugin lua scripts, so > they play nicely together. I have stopped using this and have all my SciTE > scripting in a single file - attached. > > My current windows SciTE installation for reference: > > ----+/SciTE/ > ---- Sc541.exe > ---- SciTEGlobal.properties > (ext.lua.startup.script=$(SciteDefaultHome)\SciTE.lua) > (import $(SciteDefaultHome)\mod) > ---- SciTE.lua > (This is my only script) > ----+ /mod/ > (modifications and additions to the Sc1.exe bundled properties > files) > ---- ahk.properties > ---- kix.properties > ---- lua.api > ---- lua.properties > ---- markdown.properties > ---- props.api > ---- props.properties > ---- SciTELua.api > ---- SciTELua.properties > ---- sql.properties > > SciTE is not my only editor and the script is dependent upon several > external tools/files most of which are annotated in the script (e.g. > Hunspell.exe, paste.exe, shelexec.exe, GrepWin.exe). > > I have given up on using any third party binary (DLL) addins for SciTE - > see dead batteries <https://lwn.net/Articles/812122/>. > > Kind Regards Gavin Holt > > On Thursday 18 January 2024 at 10:08:20 UTC [email protected] wrote: > >> Neil, thanks for your answer ! >> > There is https://github.com/moltenform/scite-files but I just noticed >> a link to its old location on the web page. >> Oh yes, I know well this ressource. It's an almost complete digest of >> what have been done in the SciTEsphere. >> >> BTW by "centralized ressource" I think more of something easyer for new >> adopters, like unique startup script allowing easy extensions integration >> (such as extman), videos/pictures of what can be done... the lua-users wiki >> could be a good base because of its editablility. >> >> My configs are all messy as yours (as early adopter and daily user), and >> the molteform repo is more a do-what-you-can-whith-this list :D >> >> I know SciTE purpose was at first a proof of concept for Scintilla, >> although her maturity, lightliness and flexibility give her the chance to >> be among the best editors/IDE. >> >> Pascal >> >> Le mercredi 17 janvier 2024 à 22:01:56 UTC+1, Neil Hodgson a écrit : >> >>> Pascal: >>> >>> > Actually, unless I missed something, SciTE lacks a centralised >>> ressource to allow people to easily install and configure her. >>> > There are scattered initiatives, mostly olds. Nevertheless, this group >>> and lua-users site are a good start. >>> >>> There is https://github.com/moltenform/scite-files but I just noticed a >>> link to its old location on the web page. >>> >>> > I always was curious of some people's configs, such as Neil's (which I >>> imagine is powerfull but sleek and simple) ;-) >>> >>> My configuration is always very messy as I add items to check reported >>> bugs and never clean it up properly. >>> >>> Neil >>> >>> -- You received this message because you are subscribed to the Google Groups "scite-interest" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/scite-interest/df54dae8-9833-4a0a-a7e0-f97a6116b282n%40googlegroups.com.
lusci3.lua
(text/x-lua, 13.2 KB)
--[[ From - `LuSci` https://codeberg.org/lusci/lusci
MIT License (c) 2024 A Strain, [email protected]
This Lua script for SciTE contains the neccessary helpers and
these three functions and for modifying the current selection:
keypr_sort()
toggles standard and natural sort order in selected text
keypr_twiddle()
reverses selected words or lines or column, or flips letters at caret
keypr_cyclecase() -
cycles through lower > Sentence > First Letter > ALL CAPS of selected
They are made to work with normal or monospaced rectangular selections.
--]]
-- section: imported helper functions
function GetClipboard()
local p,nl,cb = editor, "\n", nil
local a,c,l,v = p.Anchor,p.CurrentPos, p.Length, p.FirstVisibleLine
scite.SendEditor(SCI_SETUNDOCOLLECTION,false)
p:AppendText(nl) --add newline in case rectangular paste might add indents
p:SetSel(l+#nl,l+#nl)
p:Paste()
cb = p:textrange(l+#nl,p.Length)
--p:DeleteRange(l,p.Length) --DeleteRange doesnt work on output
p:SetSel(l,p.Length) p:Clear()
p:SetSel(a,c)
p.FirstVisibleLine=v
scite.SendEditor(SCI_SETUNDOCOLLECTION,true)
return cb
end
local function tain(v,bot,top) --con(tain) v=tain(v,[low or 0,[high or no high]])
bot=bot or 0
v = v==v and v or bot --sheds damn nans
if v<bot then v=bot end
if top and v>top then v=top end
return v
end
local function get_pane(p) --rt: pan,lfps,rtps,rv,anc,cur,bln,dlnadj,dltrue,plen
if not p then p=editor if output.Focus then p=output end end
local b,d,r=p.Anchor,p.CurrentPos,false
if p.CurrentPos<p.Anchor then b,d,r=d,b,true end
local bl,dl=p:LineFromPosition(b),p:LineFromPosition(d)
local dbac = bl~=dl and d==p:PositionFromLine(dl) and 1 or 0
return p,b,d,r,p.Anchor, p.CurrentPos, bl, dl-dbac, dl, p.Length
end
local function poslinestfn(cp,pane,offset,ln) --rtrns: lineSt, linefn, line
offset= offset or 0
pane=pane or editor
cp=cp or pane.CurrentPos
ln=ln or pane:LineFromPosition(tain(cp,0,pane.Length))
ln=ln+offset
if ln<0 then
return 0,0,0
elseif ln>pane.LineCount-1 then
return pane.Length,pane.Length,pane.LineCount-1
else
return pane:PositionFromLine(ln), pane.LineEndPosition[ln], ln
end
end
local function nlchar(p)
p = p or (editor.Focus and editor or output)
if p.EOLMode==0 then return "\r\n" end
if p.EOLMode==1 then return "\r" end
return "\n"
end
local function unconcat_(hay, septt, eschar) -- unconcat (hay,sep pattern[, escape char])
local insert, tbl, emtc = table.insert, {} -- not sure if needed to import here
septt=septt or "[,.| ]+"
if eschar and #eschar>0 then
eschar = eschar:gsub("%W","%%%0")
septt = eschar.."*"..septt
emtc = "("..eschar.."+)"..septt
end
local ank,fndst,fndy,fnda,fnde = 1,1,#hay
while fndst do
fnda,fnde = hay:find(septt,fndst)
if fnde then
fndst=fnde+1
fndy= fnda-1
if eschar and fnda~=fnde then -- room for escape
local esca,esce,escm=string.find(hay:sub(fnda,fnde),emtc)
if esce and (#escm)&1==1 then
fndy = nil --septt was escaped
end
end
else --no thing left
if ank<=#hay then fndy=#hay end
end
if fndy then
insert(tbl,hay:sub(ank,fndy))
ank=fnde and fnde+1 --fnde may be nil
fndst=ank --nil ends while loop
end
end
return tbl
end
local function unconcat(hay, sep, eschar) -- hay, sep = 1 plain char or pattern [,escape char]
local sep, tbl, insert, patt = sep or "", {}, table.insert
if #sep>1 or eschar then
return unconcat_(hay,sep,eschar) --complex version,
end
if #sep==0 then patt ="(.)" else
patt="([^"..sep:gsub("%W","%%%0").."]*)"
end
for c in hay:gmatch(patt) do insert(tbl,c) end
return tbl
end
local function fliptab(t)
for i=0, (#t-1)/2, 1 do t[i+1],t[#t-i] = t[#t-i],t[i+1] end
return t
end
function array_reorder(tbl,ndx) --inplace reorder tbl by ndx
local cv,bi,di
for ci=1,#tbl-1,1 do
cv,bi = tbl[ci],ci
while ndx[bi]~=bi do
di,ndx[bi] = ndx[bi],bi
if di ~= ci then
tbl[bi],bi = tbl[di],di
else
tbl[bi] = cv
end
end
end
return tbl
end
function utftotable(txt) --unicode iterator from lua manual
local utab={}
for c in string.gmatch(txt, "([%z\1-\127\194-\244][\128-\191]*)") do
table.insert(utab,c)
end
return utab
end
function hasutf(txt) return txt:find("[%z\194-\244][\128-\191]*") end
-- lookups from https://gist.github.com/natanael-b/3de34eff407477cc519eb6a309ebaf14
local utf_lower = {
[192]=224, [193]=225, [194]=226, [195]=227, [196]=228, [197]=229, [198]=230, [199]=231,
[200]=232, [201]=233, [202]=234, [203]=235, [204]=236, [205]=237, [206]=238, [207]=239,
[208]=240, [209]=241, [210]=242, [211]=243, [212]=244, [213]=245, [214]=246, [216]=248,
[217]=249, [218]=250, [219]=251, [220]=252, [221]=253, [222]=254, [376]=255 }
local utf_upper = {
[224]=192, [225]=193, [226]=194, [227]=195, [228]=196, [229]=197, [230]=198, [231]=199,
[232]=200, [233]=201, [234]=202, [235]=203, [236]=204, [237]=205, [238]=206, [239]=207,
[240]=208, [241]=209, [242]=210, [243]=211, [244]=212, [245]=213, [246]=214, [248]=216,
[249]=217, [250]=218, [251]=219, [252]=220, [253]=221, [254]=222, [255]=376 }
local function utfcaseup(str,cas)
if cas then str=string.lower(str) cas=utf_lower
else str=string.upper(str) cas=utf_upper end
if not hasutf(str) then return str end
local r= {}
for k,v in utf8.codes(str) do r[#r+1] = utf8.char( cas[v] or v ) end
return table.concat(r)
end
function upperutf8(str) return utfcaseup(str) end
function lowerutf8(str) return utfcaseup(str,"low") end
-- section: entrails of the three feature functions
local function matchout(hy,nd,plain)
--returns the matched portion and hy with matched portion removed.
--if the pattern contains captures it returns the captures concatenated instead
--of the matched portion. All matched text is discarded irregardless of captures.
if not hy or not nd then return hy, "" end
local s,e,cap,cap2,cap3 = string.find(hy,nd,1,plain) -- nd can be ^.. or ..$
if cap then cap = cap..(cap2 or "")..(cap3 or "") end
if e then
return string.sub(hy,1,s-1)..string.sub(hy,e+1) , cap or string.sub(hy,s,e)
else
return hy , ""
end
end
local function getmulsel(pan)
local s,sels = pan.Selections,{}
sels.rvs=false
for i=0,s-1 do
local a,c = pan.SelectionNAnchor[i],pan.SelectionNCaret[i]
if(c<a) then a,c=c,a sels.rvs=true end
table.insert(sels,{a,c})
end
sels.rc = pan.RectangularSelectionCaret
sels.rcv = pan.RectangularSelectionCaretVirtualSpace
sels.ra = pan.RectangularSelectionAnchor
sels.rav = pan.RectangularSelectionAnchorVirtualSpace
sels.m = pan.MainSelection
sels.p = pan sels.n = s
sels.x = false
return sels
end
local function setmulsel(sels)
local pan=sels.p
for i=1,sels.n do
if i==1 then
if sels.rvs then sels[i][1],sels[i][2]=sels[i][2],sels[i][1] end
pan:SetSelection(sels[i][2],sels[i][1]) -- setsel(caret,anchor)
else
if sels.rvs then sels[i][1],sels[i][2]=sels[i][2],sels[i][1] end
pan:AddSelection(sels[i][2],sels[i][1])
end
end
pan.MainSelection=sels.m
if sels.ra then
pan.RectangularSelectionAnchor=sels.ra
pan.RectangularSelectionAnchorVirtualSpace=sels.rav
pan.RectangularSelectionCaret=sels.rc
pan.RectangularSelectionCaretVirtualSpace=sels.rcv
end
end
function filtertext(fn,opts,aa,cc) --filters opts="sw" or (s)el or (l)ine or (a)ll
opts=opts or "esa"
local os,ow,ol,oa=opts:match("s"),opts:match("w"),opts:match("l"),opts:match("a")
local oe,oo=opts:match("e"),opts:match("o") --(o)utput (e)ditor
local pan,b,d,rv,a,c ,x,y = get_pane(oe and editor or oo and output)
if os and pan.Selections>1 then
filtermultisel(fn,pan)
return true
end
--
if aa then x,y=aa,cc
elseif os and b~=d then x,y=b,d
elseif ol then x,y=poslinestfn(b,pan)
--elseif ow then x,y=wordsomeway(pan,b,lft) --imports needed from lusci
--elseif oa then x,y=0,pan.Length
else x,y=0,pan.Length
end
local fta=pan:textrange(x,y)
local ftd=fn(fta)
if fta~=ftd then
pan:SetSel(x,y)
pan:ReplaceSel(ftd)
d=d-#fta+#ftd
if rv then pan:SetSel(d,b)
else pan:SetSel(b,d) end
end
return true
end --work out how to filter multiple sels and virtual sels...
function filtermultisel(fn,pan)
local sels=getmulsel(pan)
local s,m = sels.n,sels.m
pan:ClearSelections()
pan:BeginUndoAction()
filtermuls(fn,sels)
pan:EndUndoAction()
setmulsel(sels)
end
function filtermuls(fn,sels) --multiselection set
local pan=sels.p
local x=0
for i=1,sels.n do
local a,c = sels[i][1],sels[i][2]
a,c = a+x,c+x
local ins = fn( pan:textrange(a,c) )
pan:remove(a,c) pan:InsertText(a,ins)
sels[i][1],sels[i][2] = a, a+#ins
if c-a~=#ins then
sels.ra=false --invalidate rectangle selection mode
x=x-c+a+#ins
end
end
end
local function evocase(c)
local cz=0
local d,f,n,m
--0 all lower
--1 cap start and periods
--2 Capitalize first letters
--3 capitalize all
f = upperutf8(c)
if c==f then return lowerutf8(c) --c was all upper
else
d = lowerutf8(c)
if c==d then --c was all lower
--beginning of passage
d = c:gsub("^[^%l]*%l", upperutf8)
d = d:gsub("^[^%l]*[\192-\247][\128-\191]?[\128-\191]?[\128-\191]?", upperutf8)
--after periods, d is (1)
d = d:gsub("[.]%s-%a", upperutf8)
d = d:gsub("[.]%s-[\192-\247][\128-\191]?[\128-\191]?[\128-\191]?", upperutf8)
return d --return sentence cap
end
e = d:gsub("%f[%w_%-\192-\247].[\128-\191]?[\128-\191]?[\128-\191]?", upperutf8) --e is (2)
if c~=e then return e end
return f --returns all upper
end
end
local function togglesort(t)
local ix,t2 ={},{}
local function compa(a,b) return t[a] < t[b] end
local function compb(a,b)
local bisnum = type(t2[b])=='number'
if type(t2[a])=='number' then
if not bisnum then
return false
else return t2[a]<t2[b] end
elseif bisnum then return true
else return t2[a]<t2[b] end
end
local changed=false
for i=1,#t,1 do ix[i]=i end
for i=2,#ix,1 do
if compa(ix[i],ix[i-1]) then
changed=true
table.sort(ix,compa)
break
end
end
if not changed then
for i=1,#t,1 do
local u=t[i]:match("^%s*([^%s]+)")
u = u and tonumber(u)
t2[i]=u or t[i]:gsub("%d+",function(d) return string.format("%020d",d) end )
end
table.sort(ix,compb)
end
return array_reorder(t,ix)
end
-- section: main of three feature functions
function keypr_cyclecase()
return filtertext(evocase,"sl") --filters (s)el or (l)ine if no sel
end
function keypr_sort() return keypr_twiddle("sort") end
function keypr_twiddle(sortit) --twiddles or sorts selection
local pan,ca,ce,rv=get_pane()
local t,sels,xa,xe
local multi=pan.Selections>1
if not multi then
if ca==ce then
local d=tain(ca+1,0,pan.Length)
filtertext(function(c) return c:sub(2,2)..c:sub(1,1) end ,"-", tain(ca-1),d)
pan:SetSel(d,d)
return true
end
local tx=pan:textrange(ca,ce)
local cnt,p={},nil
xa,xe="",""
local yca,ycc,ylnn=poslinestfn(ca,pan)
local zca,zcc,zlnn=poslinestfn(ce,pan)
if ce==zcc then zca,zlnn=zcc,zlnn+1 end
if zlnn-ylnn > 1 and ca==yca and ce==zca then -- divby lines when sel at line ends
punky=nlchar()
tx,xa=matchout(tx,"^"..punky)
tx,xe=matchout(tx,punky.."$")
else
local punks={"else","==","<=","~=",">=","%)%(","%.%.","><","%]%["," = ","=",",","|",":",";","~",">","<","%+","%-","/","%.","%*","%^","&"," "," or "," and "}
local lft={"{","%(","%[","<"} --,'"',"'","`"," "} -- i think these dont keypr_twiddle
local rgt={"}","%)","%]",">"} --,'"',"'","`"," "}
local mid={"%}%{","%)%(","%]%[","><"} --,'^[^"]+$',"^[^']+$","^[^`]+$","^[^ ]+$"}
if #tx>3 then
local ya,ye,yc = tx:sub(1,1),tx:sub(-1),tx:sub(2,#tx-1)
for i=1,#lft do
if ya:find(lft[i]) and ye:find(rgt[i])
and ( yc:find(mid[i]) or not ( yc:find(lft[i],1,true) or yc:find(rgt[i],1,true) )) then
xa,xe,tx=ya,ye,yc
break
end
end
end
for i,v in pairs(punks) do
local b,c,n=0,0,0
while c and n<1000 do
b,c=tx:find(v,c+1)
if c then n=n+1 cnt[i]=(cnt[i] or 0)+1 p=i end
end
if cnt[i]==1 then break end
end
local m=321
if not p then
for i,v in pairs(cnt) do
if v>1 and v<m then m=v p=i end end
end
if not p then punky="" else punky =tx:match(punks[p]) end
if p then
punky =tx:match(punks[p])
else
punky=""
end
end
t=unconcat(tx,punky)
else
t,sels={},getmulsel(pan)
for i=1,sels.n do
if sels[i][1]~=sels[i][2] then
t[i] = pan:textrange(sels[i][1],sels[i][2])
end
end
end
if sortit then togglesort(t) else fliptab(t) end
if not multi then
pan:ReplaceSel(xa..table.concat(t,punky)..xe)
if rv then ca,ce=ce,ca end
pan:SetSel(ca,ce)
else
pan:BeginUndoAction()
for i=1,sels.n do
if sels[i][1]~=sels[i][2] then
pan:remove(sels[i][1],sels[i][2])
pan:InsertText(sels[i][1],t[i])
end
end
pan:EndUndoAction()
setmulsel(sels)
end
return true
end