-- TIME_STAMP 2021-12-05 18:05:21 v 0.3 -- coding:utf-8 -- v 0.3 added: The position in the line (indentation) is taken into account -- added: The dialogs support English and German language by default (evaluation of the "locale.properties" file). -- Other languages can be used by replacing the German terms in the "tSetIndex.t_trans" table. -- fixed: Errors when using declarations without valid ubound value. -- v 0.2 added: Static array assignment lines with/without declaration (1D/2D array) local tSetIndex = {} do tSetIndex.f_onstrip = nil tSetIndex.t_rect = {{false}} tSetIndex.s_start = nil tSetIndex.s_end = nil tSetIndex.s_mode = nil tSetIndex.s_count = nil tSetIndex.l_start = nil tSetIndex.l_end = nil tSetIndex.l_text = nil tSetIndex.indent = nil tSetIndex.i_1 = 0 tSetIndex.i_2 = 0 tSetIndex.caret = nil -- If your locale is neither English nor German, write here a unique line from your locale.properties. -- Here you can find your local properties: https://github.com/moltenform/scite-files/blob/main/files/translations_list.md tSetIndex.locale_pattern = "# Updated german translations" -- i.e.: french: "# locale.fr.properties" or italian: "# locale.it.properties" tSetIndex.t_trans = {} -- Replace the German terms with those of your language. tSetIndex.t_trans.start = {'Start value', 'Startwert'} tSetIndex.t_trans.step = {'Step size, can be combined with:', 'Schrittweite, kann kombiniert werden mit:'} tSetIndex.t_trans.start_ix = {'Start index', 'Start Index'} tSetIndex.t_trans.start_ix1 = {'Start index 1', 'Start Index 1'} tSetIndex.t_trans.start_ix2 = {'Start index 2', 'Start Index 2'} tSetIndex.t_trans.num = {'Number of elements', 'Anzahl Elemente'} tSetIndex.t_trans.num1 = {'Count 1', 'Anzahl 1'} tSetIndex.t_trans.num2 = {'Count 2', 'Anzahl 2'} tSetIndex.t_trans.apply = {'Apply', 'Übernehmen'} tSetIndex.b_locale = false tSetIndex.IsLocale = function(self) local fh = io.open(props['SciteDefaultHome']..'/locale.properties') if fh == nil then return false end -- default installation: english local s = fh:read('*a') fh:close() if s:find(self.locale_pattern) then return true end return false end tSetIndex.Ternary = function(self, _cond, _if_val, _else_val) if _cond == true then return _if_val else return _else_val end end tSetIndex.Init = function(self) self.s_start = editor.SelectionStart self.s_end = editor.SelectionEnd if self.s_start > self.s_end then self.s_start, self.s_end = self.s_end, self.s_start end self.s_mode = editor.SelectionMode self.s_count = editor.Selections self.l_start = editor:LineFromPosition(self.s_start) self.l_end = editor:LineFromPosition(self.s_end) self.b_locale = self:IsLocale() end --[[ check for declaration (Global/Local/Dim): true/false read ubound-size(declaration)/index-value(otherwise) returns: true, ubound1, ubound2 or false, index1, index2 If no array variable is selected, the following is returned: false, nil, nil ]] tSetIndex.IsDeclaration = function(self, _line) local arr1D = '%$[%w_]+%[(%d-)%]' local arr2D = '%$[%w_]+%[(%d-)%]%[(%d-)%]' local pattern = {} table.insert(pattern, '(%s-)[Gg][Ll][Oo][Bb][Aa][Ll]%s-'..arr2D) table.insert(pattern, '(%s-)[Gg][Ll][Oo][Bb][Aa][Ll]%s-'..arr1D) table.insert(pattern, '(%s-)[Ll][Oo][Cc][Aa][Ll]%s-'..arr2D) table.insert(pattern, '(%s-)[Ll][Oo][Cc][Aa][Ll]%s-'..arr1D) table.insert(pattern, '(%s-)[Dd][Ii][Mm]%s-'..arr2D) table.insert(pattern, '(%s-)[Dd][Ii][Mm]%s-'..arr1D) local indent, ub1, ub2 for i=1, #pattern do indent, ub1, ub2 = _line:match(pattern[i]) -- if 2nd index empty: ub2=='' if ub1 ~= nil then self.indent = indent return true, ub1, ub2 -- without 2nd index: ub2==nil end end -- if no declaration: detection type 1D/2D, read possible index values local indent, i1, i2 = _line:match('(%s-)'..arr2D) if i1 ~= nil then self.indent = indent return false, i1, i2 else indent, i1 = _line:match('(%s-)'..arr1D) self.indent = indent return false, i1 end end tSetIndex.InsertByDeclaration = function(self, _ub1, _ub2) local ar_type, l_ub1, l_ub2 = nil if _ub2 == nil then if (_ub1 == '' or tonumber(_ub1) == 0) then print('! FAILURE: No or no valid ubound in the declaration.') return else ar_type = 1 l_ub1 = tostring(_ub1 -1):len() end else if (_ub1 == '' or tonumber(_ub1) == 0) then print('! FAILURE: No or no valid ubound 1 in the declaration.') return else if (_ub2 == '' or tonumber(_ub2) == 0) then print('! FAILURE: No or no valid ubound 2 in the declaration.') return else l_ub1 = tostring(_ub1 -1):len() l_ub2 = tostring(_ub2 -1):len() ar_type = 2 end end end local s_insert, v, s_idx = '' v = self.l_text:match('(%$[%w_]+)%[%d-%]') if ar_type == 1 then -- 1D array for i=1, _ub1 do s_idx = ('[%s%d]'):format((' '):rep(l_ub1-tostring(i-1):len()), i-1) s_insert = s_insert..self.indent..v..s_idx..' = \n' if self.caret == nil then self.caret = self.s_end + s_insert:len() +1 end end elseif ar_type == 2 then -- 2D array for i=1, _ub1 do for j=1, _ub2 do s_idx = ('[%s%d][%s%d]'):format((' '):rep(l_ub1-tostring(i-1):len()), i-1, (' '):rep(l_ub2-tostring(j-1):len()), j-1) s_insert = s_insert..self.indent..v..s_idx..' = \n' if self.caret == nil then self.caret = self.s_end + s_insert:len() +1 end end end end local posIns = editor:PositionFromLine(self.l_start +1) editor:InsertText(posIns, s_insert) editor:SetSelection(self.caret, self.caret) end tSetIndex.StripInsertNoDeclarationAr1D = function(self, _id, _change) if _id == 4 and _change == 1 then local start, count = tonumber(scite.StripValue(1)), tonumber(scite.StripValue(3)) local i_len, s_idx = tostring(count + start):len() local s = editor:GetSelText() local v, s_insert = s:match('(%$[%w_]+)%[%d-%]'), '' for i=start, start+count-1 do s_idx = ('[%s%d]'):format((' '):rep(i_len-tostring(i):len()), i) s_insert = s_insert..self:Ternary(i==start,'',self.indent)..v..s_idx..' = \n' if self.caret == nil then self.caret = self.s_end + 3 end end editor:ReplaceSel(s_insert) editor:SetSelection(self.caret, self.caret) scite.StripShow('') end end tSetIndex.StripInsertNoDeclarationAr2D = function(self, _id, _change) if _id == 8 and _change == 1 then local start1, start2 = tonumber(scite.StripValue(1)), tonumber(scite.StripValue(3)) local count1, count2 = tonumber(scite.StripValue(5)), tonumber(scite.StripValue(7)) local i_len1, i_len2, s_idx1, s_idx2 = tostring(count1 + start1):len(), tostring(count2 + start2):len() local s = editor:GetSelText() local v, s_insert = s:match('(%$[%w_]+)%[%d-%]%[%d-%]'), '' for i=start1, start1+count1-1 do for j=start2, start2+count2-1 do s_idx = ('[%s%d][%s%d]'):format((' '):rep(i_len1-tostring(i):len()), i, (' '):rep(i_len2-tostring(j):len()), j) s_insert = s_insert..self:Ternary(i==start,'',self.indent)..v..s_idx..' = \n' if self.caret == nil then self.caret = self.s_end + 3 end end end editor:ReplaceSel(s_insert) editor:SetSelection(self.caret, self.caret) scite.StripShow('') end end tSetIndex.GetRect = function(self) local tRet, s, e = {} repeat s = editor:GetLineSelStartPosition(self.l_start) e = editor:GetLineSelEndPosition(self.l_start) if s ~= e then return end -- don't use if text is selected table.insert(tRet, {self.l_start,s}) self.l_start = self.l_start +1 self.s_count = self.s_count -1 until self.s_count == 0 self.t_rect = tRet end tSetIndex.StripRectSetIndex = function(self, _id, _change) if _id == 4 and _change == 1 then if not self.t_rect[1][1] then print('! FAILURE: The rectangular selection includes text.') scite.StripShow('') return end local start, step = scite.StripValue(1), scite.StripValue(3) local pos_add, v_ins, int local op, step = step:match('^([-*/]-)(%d+)') if tonumber(step) == 0 then print('! FAILURE: No step width is set') self.t_rect = {{false}} scite.StripShow('') return end -- set 1st value editor:InsertText(self.t_rect[1][2], start) pos_add = tostring(start):len() for i=2, #self.t_rect do if op == '-' then v_ins = tostring(start - step) elseif op == '*' then if tonumber(start) == 0 then print('! FAILURE: Multiplication by zero remains zero') self.t_rect = {{false}} scite.StripShow('') return end v_ins = tostring(start * step) elseif op == '/' then if tonumber(start) == 0 then print('! FAILURE: Any attempt to divide the zero remains zero') self.t_rect = {{false}} scite.StripShow('') return end int, frac = math.modf(start / step) if int == 0 or frac ~= 0 then print('! FAILURE: The division ( '..tostring(start)..' / '..tostring(step)..' ) does not have an integer result') self.t_rect = {{false}} scite.StripShow('') return end v_ins = tostring(start / step) else v_ins = tostring(start + step) end editor:InsertText(self.t_rect[i][2] + pos_add, v_ins) pos_add = pos_add + v_ins:len() start = tonumber(v_ins) end scite.MenuCommand(IDM_SAVE) self.t_rect = {{false}} -- reset scite.StripShow('') end end tSetIndex.ShowStripIndex = function(self) local idx = self:Ternary(self.b_locale, 2, 1) local strip_def_index = ("!'%s'[]'%s [ - * / ]'[]((%s))"):format(self.t_trans.start[idx], self.t_trans.step[idx], self.t_trans.apply[idx]) scite.StripShow(strip_def_index) scite.StripSet(1, 0) scite.StripSet(3, 1) end tSetIndex.ShowStripAr1D = function(self) local idx = self:Ternary(self.b_locale, 2, 1) local strip_def_index = ("!'%s'[]'%s'[]((%s))"):format(self.t_trans.start_ix[idx], self.t_trans.num[idx], self.t_trans.apply[idx]) scite.StripShow(strip_def_index) scite.StripSet(1, self.i_1) end tSetIndex.ShowStripAr2D = function(self) local idx = self:Ternary(self.b_locale, 2, 1) local strip_def_index = ("!'%s'[]'%s'[]'%s'[]'%s'[]((%s))"):format(self.t_trans.start_ix1[idx], self.t_trans.start_ix2[idx], self.t_trans.num1[idx], self.t_trans.num2[idx], self.t_trans.apply[idx]) scite.StripShow(strip_def_index) scite.StripSet(1, self.i_1) scite.StripSet(3, self.i_2) end end OnStrip = function(_id, _change) tSetIndex:f_onstrip(_id, _change) end tSetIndex:Init() if tSetIndex.s_mode == SC_SEL_RECTANGLE then tSetIndex.f_onstrip = tSetIndex.StripRectSetIndex tSetIndex:GetRect() tSetIndex:ShowStripIndex() elseif tSetIndex.s_mode == SC_SEL_STREAM then if tSetIndex.s_count == 1 then -- no selection or one selection over multiple lines if tSetIndex.s_start == tSetIndex.s_end then return end -- no selection if tSetIndex.l_start == tSetIndex.l_end then -- selection in one line tSetIndex.l_text = editor:GetLine(tSetIndex.l_start) local b_decl, ub1, ub2 = tSetIndex:IsDeclaration(tSetIndex.l_text) if b_decl then tSetIndex:InsertByDeclaration(ub1, ub2) else tSetIndex.i_1 = ub1 tSetIndex.i_2 = ub2 if ub2 == nil then if ub1 ~= nil then tSetIndex.f_onstrip = tSetIndex.StripInsertNoDeclarationAr1D tSetIndex:ShowStripAr1D() end else tSetIndex.f_onstrip = tSetIndex.StripInsertNoDeclarationAr2D tSetIndex:ShowStripAr2D() end end else -- selection over multiple lines output:ClearAll() print('! Selection over multiple lines.\n> This function supports either text selection in one line, i.e.: "Global $ar[10][2]", "$array[]" or rectangular selection without text selection.') end end end