def duplicate(self): if ed.get_sel_mode() != app.SEL_NORMAL: return app.msg_status(ONLY_NORM_SEL_MODE.format(DUPLICATION)) crts = ed.get_carets() if len(crts)>1: return app.msg_status(ONLY_SINGLE_CRT.format(DUPLICATION)) (cCrt, rCrt, cEnd, rEnd) = crts[0] bEmpSel = -1==rEnd bUseFLn = get_opt('duplicate_full_line_if_no_sel', True) bSkip = get_opt('duplicate_move_down', True) if bEmpSel: if not bUseFLn: return # Dup whole row row_txt = ed.get_text_line(rCrt) ed.insert(0, rCrt, row_txt+'\n') # Move crt to next row if bSkip and (rCrt+1)<ed.get_line_count(): _move_caret_down(cCrt, rCrt) return (rFr, cFr), (rTo, cTo) = minmax((rCrt, cCrt), (rEnd, cEnd)) pass; #LOG and log('(cFr , rFr , cTo , rTo) ={}',(cFr , rFr , cTo , rTo)) sel_txt = ed.get_text_substr(cFr, rFr, cTo, rTo) pass; #LOG and log('sel_txt={}',repr(sel_txt)) ed.insert(cFr, rFr, sel_txt)
def duplicate(self): if ed.get_sel_mode() != app.SEL_NORMAL: return app.msg_status(ONLY_NORM_SEL_MODE.format(DUPLICATION)) crts = ed.get_carets() if len(crts) > 1: return app.msg_status(ONLY_SINGLE_CRT.format(DUPLICATION)) (cCrt, rCrt, cEnd, rEnd) = crts[0] bEmpSel = -1 == rEnd bUseFLn = get_opt('duplicate_full_line_if_no_sel', True) bSkip = get_opt('duplicate_move_down', True) if bEmpSel: if not bUseFLn: return # Dup whole row row_txt = ed.get_text_line(rCrt) ed.insert(0, rCrt, row_txt + '\n') # Move crt to next row if bSkip and (rCrt + 1) < ed.get_line_count(): _move_caret_down(cCrt, rCrt) return (rFr, cFr), (rTo, cTo) = minmax((rCrt, cCrt), (rEnd, cEnd)) pass #LOG and log('(cFr , rFr , cTo , rTo) ={}',(cFr , rFr , cTo , rTo)) sel_txt = ed.get_text_substr(cFr, rFr, cTo, rTo) pass #LOG and log('sel_txt={}',repr(sel_txt)) ed.insert(cFr, rFr, sel_txt)
def duplicate(self): if ed.get_sel_mode() != app.SEL_NORMAL: return app.msg_status(ONLY_NORM_SEL_MODE.format(DUPLICATION)) crts = ed.get_carets() if len(crts)>1: return app.msg_status(ONLY_SINGLE_CRT.format(DUPLICATION)) (cCrt, rCrt, cEnd, rEnd) = crts[0] if -1==cEnd: # Empty sel -- dup whole row row_txt = ed.get_text_line(rCrt) ed.insert(0, rCrt, row_txt+'\n') # Move crt to next row if (rCrt+1)<ed.get_line_count(): colCrt = pos2pos(cCrt , rCrt, 'smb2col') smbCrt1 = pos2pos(colCrt, rCrt+1, 'col2smb') ed.set_caret(smbCrt1, rCrt+1) return (rFr, cFr), (rTo, cTo) = minmax((rCrt, cCrt), (rEnd, cEnd)) #pass; LOG and log('(cCrt, rCrt, cEnd, rEnd)={}',(cCrt, rCrt, cEnd, rEnd)) pass; LOG and log('(cFr , rFr , cTo , rTo) ={}',(cFr , rFr , cTo , rTo)) sel_txt = ed.get_text_substr(cFr, rFr, cTo, rTo) pass; LOG and log('sel_txt={}',repr(sel_txt)) ed.insert(cFr, rFr, sel_txt) if -1==rEnd: # or rCrt==rEnd: # Move crt to next row colCrt = pos2pos(cCrt , rCrt, 'smb2col') smbCrt1 = pos2pos(colCrt, rCrt+1, 'col2smb') ed.set_caret(smbCrt1, rCrt+1)
def run(self, mcr_id, times=1, waits=0, while_chngs=False, till_endln=False): ''' Main (and single) way to run any macro ''' pass; LOG and log('mcr_id, times, waits, while_chngs, till_endln={}',(mcr_id, times, waits, while_chngs, till_endln)) mcr = self.mcr4id.get(str(mcr_id)) if mcr is None: pass; LOG and log('no id',) return app.msg_status(_('No macros: {}').format(mcr_id)) cmds4eval = ';'.join(mcr['evl']) pass; LOG and log('nm, cmds4eval={}',(mcr['nm'], cmds4eval)) how_t = 'wait' rp_ctrl = self.tm_ctrl.get('rp_ctrl', 1000) # testing one of 1000 execution tm_wait = waits if waits>0 else self.tm_ctrl.get('tm_wait', 10) # sec start_t = datetime.datetime.now() pre_body = '' if not while_chngs else ed.get_text_all() for rp in range(times if times>0 else 0xffffffff): exec(cmds4eval) if till_endln and ed.get_carets()[0][1] == ed.get_line_count()-1: pass; LOG and log('break endln',) break #for rp if while_chngs: new_body = ed.get_text_all() if pre_body == new_body: pass; LOG and log('break no change',) break #for rp pre_body = new_body if (how_t=='wait' and (rp_ctrl-1) == rp % rp_ctrl and tm_wait < (datetime.datetime.now()-start_t).seconds): cnts = ([ dict( tp='lb' ,t=GAP ,l=GAP ,w=400 ,cap=_('Macro "{}" playback time is too long'.format(mcr['nm']))) ,dict(cid='wait' ,tp='bt' ,t=GAP*2+25*1 ,l=GAP ,w=400 ,cap=_('Wait &another {} sec').format(tm_wait) ,props='1' ) # default ,dict(cid='cont' ,tp='bt' ,t=GAP*3+25*2 ,l=GAP ,w=400 ,cap=_('Continue &without control') ) ,dict(cid='stop' ,tp='bt' ,t=GAP*6+25*3 ,l=GAP ,w=300 ,cap=_('&Cancel playback [ESC]') ) ]) btn,vals,chds= dlg_wrapper(_('Playback macro'), GAP*2+400, GAP*7+4*25, cnts, {}) if btn is None or btn=='stop': pass; LOG and log('break by user',) app.msg_status(_('Cancel playback macro: {}'.format(mcr['nm']))) break #for rp if btn=='cont': #ans=='cont': how_t = 'work' if btn=='wait': #ans=='wait': start_t = datetime.datetime.now() #for rp self.last_mcr_id = mcr_id
def _cmt_toggle_line(self, cmt_type): ''' Add/Remove line comment Params cmt_type '1st' at begin of line 'bod' at first not blank ''' if not _check_API('1.0.107'): return if ed.get_sel_mode() != app.SEL_NORMAL: return app.msg_status(ONLY_NORM_SEL_MODE.format(COMMENTING)) lex = ed.get_prop(app.PROP_LEXER_CARET) cmt_sgn = app.lexer_proc(app.LEXER_GET_COMMENT, lex) pass; LOG and log('lex, cmt_sgn={}', (lex, cmt_sgn)) if not cmt_sgn: return app.msg_status(CMT_NO_LINE_4LEX.format(lex)) crts = ed.get_carets() if len(crts)>1: return app.msg_status(ONLY_SINGLE_CRT.format(COMMENTING)) no_tab = ed.get_prop(app.PROP_TAB_SPACES) # only blanks opts = self._get_opts('cmt') save_bd_col = no_tab and opts.get('save_body_col', False) blnks4cmt = '\t'.expandtabs(len(cmt_sgn)) (cCrt, rCrt ,cEnd, rEnd)= crts[0] (rCmtBgn ,rCmtEnd) = minmax(rCrt, rEnd if -1!=rEnd else rCrt) uncmtAll = ed.get_text_line(rCmtBgn).lstrip().startswith(cmt_sgn) pass; LOG and log('rCmtBgn,rCmtEnd,uncmtAll={}', (rCmtBgn,rCmtEnd,uncmtAll)) for rCmt in range(rCmtBgn, rCmtEnd+1): line = ed.get_text_line(rCmt) pos_body= line.index(line.lstrip()) pass; LOG and log('rCmtBgn,rCmtEnd,uncmtAll={}', (rCmtBgn,rCmtEnd,uncmtAll)) if uncmtAll: # Uncomment! if not line[pos_body:].startswith(cmt_sgn): # Already no comment continue if save_bd_col: line = line.replace(cmt_sgn, blnks4cmt, 1) else: line = line.replace(cmt_sgn, '' , 1) else: # Comment! if cmt_type=='bod' and line[pos_body:].startswith(cmt_sgn): # Body comment already sets - willnot double it continue if False:pass elif cmt_type=='1st' and save_bd_col and line.startswith(blnks4cmt) : line = line.replace(blnks4cmt, cmt_sgn, 1) # elif cmt_type=='1st' and save_bd_col # !line.startswith(blnks4cmt) : elif cmt_type=='1st':# !save_bd_col line = cmt_sgn+line elif cmt_type=='bod' and save_bd_col and line.startswith(blnks4cmt) : line = line.replace(blnks4cmt, cmt_sgn, 1) line = line[:pos_body-len(cmt_sgn)]+cmt_sgn+line[pos_body:] # elif cmt_type=='bod' and save_bd_col # !line.startswith(blnks4cmt) : elif cmt_type=='bod':# !save_bd_col line = line[:pos_body] +cmt_sgn+line[pos_body:] ed.set_text_line(rCmt, line) #for rCmt if -1==rEnd and opts.get('skip-line-after', True) and (rCrt+1)<ed.get_line_count(): colCrt = pos2pos(cCrt , rCrt, 'smb2col') smbCrt1 = pos2pos(colCrt, rCrt+1, 'col2smb') ed.set_caret(smbCrt1, rCrt+1)
def _get_occurrences(ignore_min_len=False): """ Gets a tuple (items, text, is_selection, x1, y1) containing all the occurrences for the selected word or for the word under current caret. param: ignore_min_len works only with selections. """ global occurrences lex = ed.get_prop(app.PROP_LEXER_FILE) if not lex: lex = '-' if not is_lexer_ok(lex): return if ed.get_line_count() > opt.MAX_LINES: return current_text = _get_current_text() if not current_text: return text, caret_pos, is_selection = current_text log('Looking occurrences for text: "' + text + '"') if is_selection: if not ignore_min_len: if not opt.SEL_ALLOW_WHITE_SPACE: text = text.strip() if not text: return if len(text) < opt.MIN_LEN: return case_sensitive = opt.SEL_CASE_SENSITIVE words_only = opt.SEL_WORDS_ONLY whole_words = opt.SEL_WHOLE_WORDS if opt.SEL_WORDS_ONLY else False else: case_sensitive = opt.CARET_CASE_SENSITIVE words_only = True whole_words = opt.CARET_WHOLE_WORDS # Validate if current text is a 'valid word' for current lexer if words_only and not is_word(text, lex): log("Current text refused because is not a valid word") return # caret_pos have the information with sorted values x1, y1 = caret_pos[:2] # Validate if the searching word is the same of the previous occurrences if len(occurrences) > 0: prev_items = occurrences[0] prev_text = occurrences[1] if prev_text == text and (x1, y1) in prev_items: log("Returning previous occurrences") return prev_items, text, is_selection, x1, y1 items = find_all_occurrences(text, case_sensitive, whole_words) if not items or (len(items) == 1 and items[0] == (x1, y1)): return return items, text, is_selection, x1, y1
def _prep_sess(self, wdex='word'): """ Params wdex Type of sess: 'word' / 'expr' """ crts = ed.get_carets() if len(crts) > 1: return app.msg_status(_("Command doesnt work with multi-carets")) (cCrt, rCrt, cEnd, rEnd) = crts[0] if -1 != rEnd and rCrt != rEnd: return app.msg_status( _("Command doesnt work with multi-line selection")) stayed = self.sess \ and self.sess.pre_mver == ed.get_prop(app.PROP_MODIFIED_VERSION) \ and self.sess.pre_crt0 == crts[0] cEnd, rEnd = (cCrt, rCrt) if -1 == rEnd else (cEnd, rEnd) sel_be_eb = 'be' if cCrt > cEnd else 'eb' if cCrt < cEnd else '' ((rSelB, cSelB), (rSelE, cSelE)) = apx.minmax((rCrt, cCrt), (rEnd, cEnd)) pass #LOG and stayed and log('stayed,(wdex,self.sess.wdex)={}',(stayed,(wdex,self.sess.wdex))) if stayed and wdex == self.sess.wdex: # Sess OK return True what = '' # Str to find what_b = -1 # Pos what begin what_e = -1 # Pos what end kill_b = -1 # Pos kill begin kill_e = -1 # Pos kill end wbnd = True # Need left word bound sel = '' if stayed and wdex != self.sess.wdex: # Change sess type what = self.sess.src_what what_b = self.sess.src_what_b what_e = self.sess.src_what_e kill_b = self.sess.src_kill_b kill_e = self.sess.src_kill_e wbnd = self.sess.src_wbnd if not stayed: # New sess line = ed.get_text_line(rCrt) sel = ed.get_text_sel() if sel: # Use selection to find what = sel what_b = cSelB what_e = cSelE wbnd = 0 == cSelB or line[cSelB - 1].isspace() else: # Use "chars around caret" to find what tx_bfr = line[:cCrt] ch_bfr = tx_bfr[-1] if tx_bfr else ' ' tx_aft = line[cCrt:] ch_aft = tx_aft[0] if tx_aft else ' ' pass #LOG and log('ch_bfr,ch_aft,tx_bfr,tx_aft={}',(ch_bfr,ch_aft,tx_bfr,tx_aft)) shf_l = 0 shf_r = 0 if ch_bfr.isalnum() or ch_bfr in self.wdsgns: tx_bfr_r = ''.join(reversed(tx_bfr)) shf_l = len(self.base_re.match(tx_bfr_r).group()) if ch_aft.isalnum() or ch_aft in self.wdsgns: shf_r = len(self.base_re.match(tx_aft).group()) what_b = cCrt - shf_l if self.kill: what_e = cCrt kill_b = cCrt kill_e = cCrt + shf_r else: what_e = cCrt + shf_r what = line[what_b:what_e] pass #LOG and log('(shf_l,shf_r), (what_b,what_e), what={}',((shf_l,shf_r), (what_b,what_e), what)) if not what \ or not what.strip(): return app.msg_status(_('No data for search')) if len(what) < self.min_len: return app.msg_status( f(_('Need |base|>={}, but |"{}"|=={}'), self.min_len, what, len(what))) pass #LOG and log('what,wbnd={}',(what,wbnd)) asword = wdex == 'word' asexpr = wdex == 'expr' # Make new Sess if not stayed: pass #LOG and log('new sess',()) self.sess = Command.Sess() self.sess.row = rCrt self.sess.sel_sub = sel_be_eb self.sess.src_crt = cCrt self.sess.src_what = what self.sess.src_what_b = what_b self.sess.src_what_e = what_e self.sess.src_kill_b = kill_b self.sess.src_kill_e = kill_e self.sess.src_wbnd = wbnd self.sess.wdex = wdex what_re = re.compile('' + (r'\b' if wbnd else '') + re.escape(what) + (self.wdcmpl if asword else self.excmpl)) # + r'[\w'+re.escape(self.wdsgns)+']+') pass #LOG and log('what_re={}',(what_re.pattern)) bids_d = OrdDict() for line_n in range(ed.get_line_count()): if line_n == self.sess.row: continue #for line_n line = ed.get_text_line(line_n) if asexpr and self.expair: # Find+expand upto close brackets/quotes lbids_l = [] for m in what_re.finditer(line): lbid = m.group(0) ok = False for op, cl in self.opn2cls.items(): if op in lbid and lbid.count(op) > lbid.count( cl): # Try expand to good cl ext_bgn = m.end() ext_end = line.find(cl, ext_bgn) while -1 != ext_end: lbid_ext = lbid + line[ext_bgn:ext_end + 1] if lbid_ext.count(op) == lbid_ext.count(cl): lbid, ok = lbid_ext, True break #while ext_end = line.find(cl, ext_end + 1) if ok: break #for op #for op ok = False for qu in self.quotes: if qu in lbid and 1 == lbid.count( qu) % 2: # Try expand to good qu ext_bgn = m.end() ext_end = line.find(qu, ext_bgn) while -1 != ext_end: lbid_ext = lbid + line[ext_bgn:ext_end + 1] if 0 == lbid_ext.count(qu) % 2: lbid, ok = lbid_ext, True break #while ext_end = line.find(cl, ext_end + 1) if ok: break #for qu #for qu lbids_l.append(lbid) #for m else: # Find only lbids_l = what_re.findall(line) if lbids_l: bids_d.update({ bid: line_n for bid in lbids_l if bid not in bids_d or abs(line_n - self.sess.row) < abs( bids_d[bid] - self.sess.row) }) # closest if not bids_d: return app.msg_status(_('No in-text completions')) self.sess.bids = list(bids_d.keys()) self.sess.bids_c = list(bids_d.values()) self.sess.bids_i= min([(abs(bid_r-self.sess.row), bid_i) for (bid_i,bid_r) in enumerate(self.sess.bids_c) ])[1] \ if len(self.sess.bids)>1 and self.near else \ 0 self.incr_bfr = False # Dont increment before use pass #LOG and log('bids={}',(list(zip(self.sess.bids, self.sess.bids_c)))) pass #LOG and log('sess={}',(self.sess)) pass #return False return True
def find_cb_string(self, updn, bgn_crt_fin='crt'): ''' Find clipboard value in text. Params updn 'up'|'dn' - direction bgn_crt_fin 'bgn'|'crt'|'fin' - start point ''' clip = app.app_proc(app.PROC_GET_CLIP, '') if ''==clip: return clip = clip.replace('\r\n', '\n').replace('\r', '\n') pass; #LOG and log('clip={}',repr(clip)) crts = ed.get_carets() if len(crts)>1: return app.msg_status(ONLY_SINGLE_CRT.format('Command')) # Prepare bgn-, crt-, fin-point (cBgn, rBgn) = (0, 0) (cCrt, rCrt ,cEnd, rEnd) = crts[0] lst_line_ind = ed.get_line_count()-1 lst_line = ed.get_text_line(lst_line_ind) (cFin, rFin) = (max(0, len(lst_line)-1), lst_line_ind) if bgn_crt_fin=='crt': # Some cases for natural (not wrap) find if updn=='dn' and (cFin, rFin) == (cCrt, rCrt): # Caret at finish - immediately find from start return self.find_cb_string(updn, bgn_crt_fin='bgn') if updn=='up' and (cBgn, rBgn) == (cCrt, rCrt): # Caret at start - immediately find from finish return self.find_cb_string(updn, bgn_crt_fin='fin') if updn=='dn' and (cBgn, rBgn) == (cCrt, rCrt): # Caret already at start - switch wrap off bgn_crt_fin = 'bgn' if updn=='up' and (cFin, rFin) == (cCrt, rCrt): # Caret already at finish - switch wrap off bgn_crt_fin = 'fin' (cPnt, rPnt ,cEnd, rEnd) = apx.icase(False,0 ,bgn_crt_fin=='bgn', (cBgn, rBgn, cBgn, rBgn) ,bgn_crt_fin=='crt', (cCrt, rCrt, cEnd, rEnd) ,bgn_crt_fin=='fin', (cFin, rFin, cFin, rFin) ) # Main part if '\n' not in clip: # 1) Find inside each line row = rPnt line = ed.get_text_line(row) pos = line.find(clip, cPnt) if updn=='dn' else line.rfind(clip, 0, cPnt) while -1==pos: row = apx.icase(updn=='dn', row+1, updn=='up', row-1, -1) if row<0 or row==ed.get_line_count(): break #while line = ed.get_text_line(row) pos = line.find(clip) if updn=='dn' else line.rfind(clip) if False:pass elif -1==pos and bgn_crt_fin!='crt': return app.msg_status(FIND_FAIL_FOR_STR.format(clip)) elif -1==pos:#and bgn_crt_fin=='crt' # Wrap! return self.find_cb_string(updn, bgn_crt_fin=apx.icase(updn=='dn', 'bgn', 'fin')) elif updn=='dn': ed.set_caret(pos+len(clip), row, pos, row) elif updn=='up': ed.set_caret(pos, row, pos+len(clip), row) return # 2) Find m-line pass; #LOG and log('') clpls = clip.split('\n') pass; #LOG and log('clpls={}',(clpls)) clip = repr(clip) if False:pass elif updn=='dn': found = False row = max(rPnt, rEnd if rEnd!=-1 else rPnt) if row+len(clpls) < ed.get_line_count(): txtls = [ed.get_text_line(r) for r in range(row, row+len(clpls))] pass; #LOG and log('txtls={}',(txtls)) while True: if self._find_cb_string_included_mlines(txtls, clpls): # Found! found = True break #while row = row+1 pass; #LOG and log('row={}',(row)) if row+len(clpls) >= ed.get_line_count(): pass; #LOG and log('nfnd12',) break #while txtls = txtls[1:]+[ed.get_text_line(row+len(clpls)-1)] pass; #LOG and log('txtls={}',(txtls)) #while if False:pass elif not found and bgn_crt_fin!='crt': return app.msg_status(FIND_FAIL_FOR_STR.format(clip)) elif not found:#and bgn_crt_fin=='crt' # Wrap! return self.find_cb_string(updn, bgn_crt_fin=apx.icase(updn=='dn', 'bgn', 'fin')) ed.set_caret(len(clpls[-1]), row+len(clpls)-1, len(txtls[0])-len(clpls[0]), row) elif updn=='up': found = False row = min(rPnt, rEnd if rEnd!=-1 else rPnt) if row-len(clpls)+1 >= 0: txtls = [ed.get_text_line(r) for r in range(row-len(clpls)+1, row+1)] pass; #LOG and log('txtls={}',(txtls)) while True: if self._find_cb_string_included_mlines(txtls, clpls): # Found! found = True break #while row = row-1 pass; #LOG and log('row={}',(row)) if row-len(clpls)+1 < 0: break #while txtls = [ed.get_text_line(row-len(clpls)+1)]+txtls[:-1] pass; #LOG and log('txtls={}',(txtls)) #while if False:pass elif not found and bgn_crt_fin!='crt': return app.msg_status(FIND_FAIL_FOR_STR.format(clip)) elif not found:#and bgn_crt_fin=='crt' # Wrap! return self.find_cb_string(updn, bgn_crt_fin=apx.icase(updn=='dn', 'bgn', 'fin')) ed.set_caret(len(clpls[-1]), row, len(txtls[0])-len(clpls[0]), row-len(clpls)+1)
def run(self, mcr_id, times=1, waits=0, while_chngs=False, till_endln=False): ''' Main (and single) way to run any macro ''' pass; LOG and log('mcr_id, times, waits, while_chngs, till_endln={}',(mcr_id, times, waits, while_chngs, till_endln)) mcr = self.mcr4id.get(str(mcr_id)) if mcr is None: pass; LOG and log('no id',) return app.msg_status('No macros: {}'.format(mcr_id)) cmds4eval = ';'.join(mcr['evl']) pass; LOG and log('nm, cmds4eval={}',(mcr['nm'], cmds4eval)) how_t = 'wait' rp_ctrl = self.tm_ctrl.get('rp_ctrl', 1000) # testing one of 1000 execution tm_wait = waits if waits>0 else self.tm_ctrl.get('tm_wait', 10) # sec start_t = datetime.datetime.now() pre_body = '' if not while_chngs else ed.get_text_all() for rp in range(times if times>0 else 0xffffffff): exec(cmds4eval) if till_endln and ed.get_carets()[0][1] == ed.get_line_count()-1: pass; LOG and log('break endln',) break #for rp if while_chngs: new_body = ed.get_text_all() if pre_body == new_body: pass; LOG and log('break no change',) break #for rp pre_body = new_body if (how_t=='wait' and (rp_ctrl-1) == rp % rp_ctrl and tm_wait < (datetime.datetime.now()-start_t).seconds): WD_BTN = 220 ans = app.dlg_custom( 'Playback macro', GAP*2+WD_BTN, GAP*7+4*25, '\n'.join([] +[C1.join(['type=label' ,POS_FMT(l=GAP, t=GAP*1+25*0+3, r=GAP+WD_BTN, b=0) ,'cap=Macro playback time is too long' ] # i=0 )] +[C1.join(['type=button' ,POS_FMT(l=GAP, t=GAP*2+25*1, r=GAP+WD_BTN, b=0) ,'cap=Wait &another {} sec'.format(tm_wait) ] # i=1 )] +[C1.join(['type=button' ,POS_FMT(l=GAP, t=GAP*3+25*2, r=GAP+WD_BTN, b=0) ,'cap=Continue &without control' ] # i=2 )] +[C1.join(['type=button' ,POS_FMT(l=GAP, t=GAP*6+25*3, r=GAP+WD_BTN, b=0) ,'cap=&Cancel playback [ESC]' ] # i=3 )] ), 1) # start focus pass; #LOG and log('ans={}',ans) ans =('break' if ans is None else 'break' if ans[0]==3 else 'wait' if ans[0]==1 else 'cont' if ans[0]==2 else 'break') if ans=='cont': how_t = 'work' if ans=='wait': start_t = datetime.datetime.now() if ans=='break': pass; LOG and log('break by user',) break #for rp #for rp self.last_mcr_id = mcr_id
def run(self, mcr_id, times=1, waits=0, while_chngs=False, till_endln=False): ''' Main (and single) way to run any macro ''' pass LOG and log('mcr_id, times, waits, while_chngs, till_endln={}', (mcr_id, times, waits, while_chngs, till_endln)) mcr = self.mcr4id.get(str(mcr_id)) if mcr is None: pass LOG and log('no id', ) return app.msg_status('No macros: {}'.format(mcr_id)) cmds4eval = ';'.join(mcr['evl']) pass LOG and log('nm, cmds4eval={}', (mcr['nm'], cmds4eval)) how_t = 'wait' rp_ctrl = self.tm_ctrl.get('rp_ctrl', 1000) # testing one of 1000 execution tm_wait = waits if waits > 0 else self.tm_ctrl.get('tm_wait', 10) # sec start_t = datetime.datetime.now() pre_body = '' if not while_chngs else ed.get_text_all() for rp in range(times if times > 0 else 0xffffffff): exec(cmds4eval) if till_endln and ed.get_carets()[0][1] == ed.get_line_count() - 1: pass LOG and log('break endln', ) break #for rp if while_chngs: new_body = ed.get_text_all() if pre_body == new_body: pass LOG and log('break no change', ) break #for rp pre_body = new_body if (how_t == 'wait' and (rp_ctrl - 1) == rp % rp_ctrl and tm_wait < (datetime.datetime.now() - start_t).seconds): WD_BTN = 220 ans = app.dlg_custom( 'Playback macro', GAP * 2 + WD_BTN, GAP * 7 + 4 * 25, '\n'.join([] + [ C1.join([ 'type=label', POS_FMT(l=GAP, t=GAP * 1 + 25 * 0 + 3, r=GAP + WD_BTN, b=0), 'cap=Macro playback time is too long' ] # i=0 ) ] + [ C1.join([ 'type=button', POS_FMT( l=GAP, t=GAP * 2 + 25 * 1, r=GAP + WD_BTN, b=0 ), 'cap=Wait &another {} sec'.format(tm_wait) ] # i=1 ) ] + [ C1.join([ 'type=button', POS_FMT( l=GAP, t=GAP * 3 + 25 * 2, r=GAP + WD_BTN, b=0), 'cap=Continue &without control' ] # i=2 ) ] + [ C1.join([ 'type=button', POS_FMT( l=GAP, t=GAP * 6 + 25 * 3, r=GAP + WD_BTN, b=0), 'cap=&Cancel playback [ESC]' ] # i=3 ) ]), 1) # start focus pass #LOG and log('ans={}',ans) ans = ('break' if ans is None else 'break' if ans[0] == 3 else 'wait' if ans[0] == 1 else 'cont' if ans[0] == 2 else 'break') if ans == 'cont': how_t = 'work' if ans == 'wait': start_t = datetime.datetime.now() if ans == 'break': pass LOG and log('break by user', ) break #for rp #for rp self.last_mcr_id = mcr_id
def _prep_sess(self, wdex='word'): """ Params wdex Type of sess: 'word' / 'expr' """ crts = ed.get_carets() if len(crts)>1: return app.msg_status(_("Command doesnt work with multi-carets")) (cCrt, rCrt ,cEnd, rEnd)= crts[0] if -1!=rEnd and rCrt!=rEnd: return app.msg_status(_("Command doesnt work with multi-line selection")) stayed = self.sess \ and self.sess.pre_mver == ed.get_prop(app.PROP_MODIFIED_VERSION) \ and self.sess.pre_crt0 == crts[0] cEnd, rEnd = (cCrt, rCrt) if -1==rEnd else (cEnd, rEnd) sel_be_eb = 'be' if cCrt>cEnd else 'eb' if cCrt<cEnd else '' ((rSelB, cSelB) ,(rSelE, cSelE))= apx.minmax((rCrt, cCrt), (rEnd, cEnd)) pass; #LOG and stayed and log('stayed,(wdex,self.sess.wdex)={}',(stayed,(wdex,self.sess.wdex))) if stayed and wdex==self.sess.wdex: # Sess OK return True what = '' # Str to find what_b = -1 # Pos what begin what_e = -1 # Pos what end kill_b = -1 # Pos kill begin kill_e = -1 # Pos kill end wbnd = True # Need left word bound sel = '' if stayed and wdex!=self.sess.wdex: # Change sess type what = self.sess.src_what what_b = self.sess.src_what_b what_e = self.sess.src_what_e kill_b = self.sess.src_kill_b kill_e = self.sess.src_kill_e wbnd = self.sess.src_wbnd if not stayed: # New sess line = ed.get_text_line(rCrt) sel = ed.get_text_sel() if sel: # Use selection to find what = sel what_b = cSelB what_e = cSelE wbnd = 0==cSelB or line[cSelB-1].isspace() else: # Use "chars around caret" to find what tx_bfr = line[:cCrt ] ch_bfr = tx_bfr[-1] if tx_bfr else ' ' tx_aft = line[ cCrt:] ch_aft = tx_aft[ 0] if tx_aft else ' ' pass; #LOG and log('ch_bfr,ch_aft,tx_bfr,tx_aft={}',(ch_bfr,ch_aft,tx_bfr,tx_aft)) shf_l = 0 shf_r = 0 if ch_bfr.isalnum() or ch_bfr in self.wdsgns: tx_bfr_r= ''.join(reversed(tx_bfr)) shf_l = len(self.base_re.match(tx_bfr_r).group()) if ch_aft.isalnum() or ch_aft in self.wdsgns: shf_r = len(self.base_re.match(tx_aft).group()) what_b = cCrt-shf_l if self.kill: what_e = cCrt kill_b = cCrt kill_e = cCrt+shf_r else: what_e = cCrt+shf_r what = line[what_b:what_e] pass; #LOG and log('(shf_l,shf_r), (what_b,what_e), what={}',((shf_l,shf_r), (what_b,what_e), what)) if not what \ or not what.strip(): return app.msg_status(_('No data for search')) if len(what) < self.min_len: return app.msg_status(f(_('Need |base|>={}, but |"{}"|=={}'), self.min_len, what, len(what))) pass; #LOG and log('what,wbnd={}',(what,wbnd)) asword = wdex=='word' asexpr = wdex=='expr' # Make new Sess if not stayed: pass; #LOG and log('new sess',()) self.sess = Command.Sess() self.sess.row = rCrt self.sess.sel_sub = sel_be_eb self.sess.src_crt = cCrt self.sess.src_what = what self.sess.src_what_b= what_b self.sess.src_what_e= what_e self.sess.src_kill_b= kill_b self.sess.src_kill_e= kill_e self.sess.src_wbnd = wbnd self.sess.wdex = wdex what_re = re.compile('' + (r'\b' if wbnd else '') + re.escape(what) + (self.wdcmpl if asword else self.excmpl) ) # + r'[\w'+re.escape(self.wdsgns)+']+') pass; #LOG and log('what_re={}',(what_re.pattern)) bids_d = OrdDict() for line_n in range(ed.get_line_count()): if line_n == self.sess.row: continue#for line_n line = ed.get_text_line(line_n) if asexpr and self.expair: # Find+expand upto close brackets/quotes lbids_l = [] for m in what_re.finditer(line): lbid = m.group(0) ok = False for op, cl in self.opn2cls.items(): if op in lbid and lbid.count(op) > lbid.count(cl): # Try expand to good cl ext_bgn = m.end() ext_end = line.find(cl, ext_bgn) while -1!=ext_end: lbid_ext = lbid + line[ext_bgn:ext_end+1] if lbid_ext.count(op) == lbid_ext.count(cl): lbid,ok = lbid_ext, True break#while ext_end = line.find(cl, ext_end+1) if ok: break#for op #for op ok = False for qu in self.quotes: if qu in lbid and 1 == lbid.count(qu) % 2: # Try expand to good qu ext_bgn = m.end() ext_end = line.find(qu, ext_bgn) while -1!=ext_end: lbid_ext = lbid + line[ext_bgn:ext_end+1] if 0 == lbid_ext.count(qu) % 2: lbid,ok = lbid_ext, True break#while ext_end = line.find(cl, ext_end+1) if ok: break#for qu #for qu lbids_l.append(lbid) #for m else: # Find only lbids_l = what_re.findall(line) if lbids_l: bids_d.update({bid:line_n for bid in lbids_l if bid not in bids_d or abs(line_n-self.sess.row)<abs(bids_d[bid]-self.sess.row) }) # closest if not bids_d: return app.msg_status(_('No in-text completions')) self.sess.bids = list(bids_d.keys()) self.sess.bids_c= list(bids_d.values()) self.sess.bids_i= min([(abs(bid_r-self.sess.row), bid_i) for (bid_i,bid_r) in enumerate(self.sess.bids_c) ])[1] \ if len(self.sess.bids)>1 and self.near else \ 0 self.incr_bfr = False # Dont increment before use pass; #LOG and log('bids={}',(list(zip(self.sess.bids, self.sess.bids_c)))) pass; #LOG and log('sess={}',(self.sess)) pass; #return False return True