def match_ed(self, ed): """ returns: bool - is appropriate for specified Editor * Checks: 'selector', 'file_patterns' """ fn = ed.get_filename() if fn and self.file_patterns: if any( fnmatch(name=fn, pat=pattern) for pattern in self.file_patterns): pass LOG and log('build match: inbuild: file({}): {}'.format( fn, self.name)) return True lex = ed.get_prop(PROP_LEXER_FILE) if lex and self.selectors: lex = lex.lower() for sel in self.selectors: if lex == sel: pass LOG and log('build match: inbuild: lex: {}'.format(sel)) return True return False
def _get_ed_build(self, ed): filepath = ed.get_filename() if not filepath: return # custom file-type association ext_masks = list(EXTMAP) ext_masks.sort(key=lambda s: len(s), reverse=True) # from most specific bnames = (EXTMAP[mask] for mask in ext_masks if fnmatch(filepath, mask)) # matching build-names # might be associated to missing build.. search build = get_first((self._getbuild(bname) for bname in bnames), notnone=True) if build: pass LOG and log('build match: ext: {}'.format(build.name)) return build # custom lexer association edlex = ed.get_prop(PROP_LEXER_FILE) if edlex and edlex in LEXMAP: build = self._getbuild(LEXMAP[edlex]) if build: pass LOG and log('build match: lex: {}'.format(edlex)) return build # sublime selectors for b in self.builds: if b.match_ed(ed): return b
def on_macro(self, ed_self, mcr_record): ''' Finish for macro-recording. Params mcr_record "\n"-separated list of number number,string py:string_module,string_method,string_param ''' pass; LOG and log('mcr_record={}',mcr_record) if ''==mcr_record: return app.msg_status('Empty record') def_nm = '' nms = [mcr['nm'] for mcr in self.macros] for num in range(1,1000): def_nm = 'Macro{}'.format(num) if def_nm not in nms: break #for num while True: mcr_nm = app.dlg_input('Macro name. Tricks: "!NM" overwrite NM, "=NM" show NM in dialog', def_nm) if mcr_nm is None: return mcr_nm = mcr_nm.strip() if ''==mcr_nm: continue #while if mcr_nm[0]=='=': self.need_dlg = True mcr_nm = mcr_nm[1:] use_old = False if ''==mcr_nm: continue #while if mcr_nm[0]=='!': use_old = True mcr_nm = mcr_nm[1:] if ''!=mcr_nm: break #while pass; LOG and log('self.need_dlg, use_old, mcr_nm={}',(self.need_dlg, use_old, mcr_nm)) if use_old and mcr_nm in nms: mcr_ind = nms.index(mcr_nm) self.macros[mcr_ind]['rec'] = mcr_record self.macros[mcr_ind]['evl'] = self._record_data_to_cmds(mcr_record) id4mcr = self.macros[mcr_ind]['id'] else: while mcr_nm in nms: app.msg_box('Select other name.\nMacros names now:\n\n'+'\n'.join(nms), app.MB_OK) mcr_nm = app.dlg_input('Macro name', mcr_nm) if mcr_nm is None: return id4mcr = random.randint(10000, 99999) while id4mcr in self.mcr4id: id4mcr = random.randint(10000, 99999) self.macros += [{'id' :id4mcr ##?? conflicts? ,'nm' :mcr_nm ,'rec':mcr_record ,'evl':self._record_data_to_cmds(mcr_record) }] self._do_acts() if self.need_dlg: self.need_dlg = False self.last_mcr_id= id4mcr self.dlg_config()
def _record_data_to_cmds(self, rec_data): ''' Coverting from record data to list of API command Param rec_data "\n"-separated list of number number,string py:string_module,string_method,string_param ''' # Native converting evls = [] rcs = rec_data.splitlines() for rc in rcs: if False:pass elif rc[0] in '0123456789': if rc in self.CMD_ID2NM: # For ed.cmd(id) evls += ['ed.cmd(cmds.{})'.format(self.CMD_ID2NM[rc])] continue #for rc if ',' in rc: (id_cmd ,tx_cmd)= rc[0:rc.index(',')], rc[1+rc.index(','):] if ''==id_cmd.strip('0123456789') and id_cmd in self.CMD_ID2NM: # For ed.cmd(id, text) evls += ["ed.cmd(cmds.{},{})".format(self.CMD_ID2NM[id_cmd], repr(tx_cmd))] continue #for rc elif rc.startswith('py:cuda_macros,'): # Skip macro-tools continue #for rc elif rc[0:3]=='py:': # Plugin cmd evls += ["app.app_proc(app.PROC_EXEC_PLUGIN, '{}')".format(rc[3:])] continue #for rc pass; LOG and log('unknown rec-item: {}',rc) # return evls # Optimization # (1) ed.cmd(cmds.cCommand_TextInsert,'A') # ed.cmd(cmds.cCommand_TextInsert,'B') # convert to # ed.cmd(cmds.cCommand_TextInsert,'AB') has_TI = 1<len([evl for evl in evls if 'cmds.cCommand_TextInsert,' in evl]) if has_TI: reTI2 = re.compile( r"ed.cmd\(cmds.cCommand_TextInsert,'(.+)'\)" + C1 + r"ed.cmd\(cmds.cCommand_TextInsert,'(.+)'\)") evls_c1 = C1.join(evls) (evls_c1 ,rpls) = reTI2.subn( r"ed.cmd(cmds.cCommand_TextInsert,'\1\2')", evls_c1) while 0 < rpls: (evls_c1 ,rpls) = reTI2.subn( r"ed.cmd(cmds.cCommand_TextInsert,'\1\2')", evls_c1) evls = evls_c1.split(C1) #if has_TI pass; LOG and log('evls={}',evls) return evls
def run_cmd(self, cmdname): import subprocess proj_err = [False] cmdj = self._get_cmd(cmdname) cmdj = self._expand_cmd(cmdj, proj_err=proj_err) env = {**os.environ} cmd = cmdj.get('shell_cmd') or cmdj.get('cmd') is_shell = cmdj['shell'] if 'shell' in cmdj else 'shell_cmd' in cmdj cwd = cmdj.get('working_dir') file_regex = cmdj.get('file_regex') env.update(cmdj.get('env', {})) # add to environ instead of replacing path = cmdj.get('path') or cmdj.get("PATH") if path: curpath = env.get('PATH', '') path = expandvars(path, mp={'$PATH': curpath, '$path': curpath}) env['PATH'] = path set_output_regex(file_regex) pass LOG and log('?? Popen cmd={}', cmd) try: cmd_str = ' '.join(cmd) if type(cmd) == list else cmd msg_status(_('Running: "{}"').format(cmd_str)) popen = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=is_shell, env=env, cwd=cwd, ) except Exception as ex: msg_box('{}: {}'.format(type(ex).__name__, ex), MB_ICONWARNING) pass LOG and log('fail Popen', ) return if popen is None: pass LOG and log('fail Popen', ) msg_status(_('Fail running: {}').format(cmd)) return pass LOG and log('ok Popen', ) app_log(LOG_CLEAR, '', panel=LOG_PANEL_OUTPUT) notif = None if proj_err[0]: notif = _('Note: build-system is expecting a Project to be opened') return popen, cmdj, notif
def dlg_export(self): ''' Show dlg for export some macros. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status(_('Need update CudaText')) if 0==len(self.macros): return app.msg_status(_('No macros for export')) exp_file= app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') exp_file= '' if exp_file is None else exp_file exp_file= exp_file+('' if ''==exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') (WD_LST ,HT_LST)= (500 ,500) lmcrs = len(self.macros) crt,sels= '0', ['0'] * lmcrs while True: pass; LOG and log('sels={}',sels) cnts = ([ dict( tp='lb' ,tid='file' ,l=GAP ,w=70 ,cap=_('Export &to') ) ,dict(cid='file' ,tp='ed' ,t=GAP ,l=GAP+70 ,r=GAP+WD_LST-35 ,en='0' ) ,dict(cid='brow' ,tp='bt' ,tid='file' ,l=GAP+HT_LST-35 ,r=GAP+WD_LST ,cap=_('&...') ) ,dict(cid='mcrs' ,tp='ch-lbx',t=35 ,h=HT_LST ,l=GAP ,w= WD_LST ,items=[mcr['nm'] for mcr in self.macros]) ,dict(cid='ch-a' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP*1 ,w=100 ,cap=_('Check &all') ) ,dict(cid='ch-n' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP*2+100 ,w=100 ,cap=_('U&ncheck all') ) ,dict(cid='expo' ,tp='bt' ,t=GAP+35+HT_LST ,l= WD_LST-70*2 ,w=70 ,cap=_('&Export') ,props='1' ) # default ,dict(cid='-' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP+WD_LST-70*1 ,w=70 ,cap=_('Close') ) ]) vals = dict( file=exp_file ,mcrs=(crt, sels) ) btn, \ vals, \ chds = dlg_wrapper(_('Export macros') ,GAP+WD_LST+GAP, GAP*5+HT_LST+25*2-GAP, cnts, vals, focus_cid='mrcs') if btn is None or btn=='-': return crt,sels= vals['mcrs'] pass; LOG and log('sels={}',sels) if False:pass elif btn=='brow': #ans_s=='file': new_exp_file= app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') if new_exp_file is not None: exp_file = new_exp_file exp_file = exp_file+('' if ''==exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') elif btn=='ch-a': #ans_s=='all': sels = ['1'] * lmcrs elif btn=='ch-n': #ans_s=='no': sels = ['0'] * lmcrs elif btn=='expo': #ans_s=='exp': if '1' not in sels: app.msg_box(_('Select some names'), app.MB_OK) continue self.export_to_file(exp_file, [mcr for (ind, mcr) in enumerate(self.macros) if sels[ind]=='1']) return
def _stop(self): pass LOG and log('* Finished Building') timer_proc(TIMER_STOP, self._on_timer, 0) self.readthread.m_stop()
def replace_all_sel_to_cb(self): pass; LOG and log('ok',) pass; return crts = ed.get_carets() if len(crts)>1: return app.msg_status(ONLY_SINGLE_CRT.format('Command')) (cCrt, rCrt, cEnd, rEnd) = crts[0]
def __init__(self): cmd_nms = [ nm for nm in dir(cmds) if nm.startswith('cCommand_') or nm.startswith('cmd_') ] cmd_nm2id = {nm: eval('cmds.{}'.format(nm)) for nm in cmd_nms} self.CMD_ID2NM = {str(cmd_id): nm for nm, cmd_id in cmd_nm2id.items()} if len(self.CMD_ID2NM) < len(cmd_nm2id): app.msg_status('Repeated values in cudatext_cmd.py') pass #LOG and log('cmd_nm2id={}',cmd_nm2id) pass #LOG and log('CMD_ID2NM={}',self.CMD_ID2NM) ver_macros = apx._json_loads( open(MACROS_JSON).read()) if os.path.exists(MACROS_JSON) else { 'ver': JSON_FORMAT_VER, 'list': [] } if ver_macros['ver'] < JSON_FORMAT_VER: # Adapt to new format pass self.tm_ctrl = ver_macros.get('tm_ctrl', {}) self.dlg_prs = ver_macros.get('dlg_prs', {}) self.macros = ver_macros['list'] self.mcr4id = {str(mcr['id']): mcr for mcr in self.macros} self.need_dlg = False self.last_mcr_id = 0 pass LOG and log('\n\n\nMacros start', )
def build(self, name=MAIN_CMD_NAME): pass LOG and log('.build({})'.format(name)) if not ed.get_filename(): msg_status(_('Save document to disk before building')) return b = self._get_ed_build(ed) if not b: lex = ed.get_prop(PROP_LEXER_FILE) if lex: msg = _('No build-system(s) found for lexer ') + lex else: msg = _('No build-system(s) found for file ' ) + os.path.basename(ed.get_filename()) msg_status(msg) return if name is None: cmd_names = b.list_commands() ind = dlg_menu(DMENU_LIST, cmd_names, caption=_('Build with...')) if ind is None: return name = cmd_names[ind] self._run_build_cmd(b, name)
def dlg_import(self): ''' Show dlg for import some macros. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status(_('Need update CudaText')) (imp_file ,mcrs) = self.dlg_import_choose_mcrs() if imp_file is None: return lmcrs = len(mcrs) WD_LST, \ HT_LST = (500 ,500) crt,sels= '0', ['1'] * lmcrs while True: cnts = ([ dict( tp='lb' ,tid='file' ,l=GAP ,w=85 ,cap=_('Import &from') ) ,dict(cid='file' ,tp='ed' ,t=GAP ,l=GAP+85 ,r=GAP+WD_LST-35 ,en='0' ) ,dict(cid='brow' ,tp='bt' ,tid='file' ,l=GAP+HT_LST-35 ,r=GAP+WD_LST ,cap=_('&...') ) ,dict(cid='mcrs' ,tp='ch-lbx',t=35 ,h=HT_LST ,l=GAP ,w= WD_LST ,items=[mcr['nm'] for mcr in mcrs] ) ,dict(cid='ch-a' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP*1 ,w=100 ,cap=_('Check &all') ) ,dict(cid='ch-n' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP*2+100 ,w=100 ,cap=_('U&ncheck all') ) ,dict(cid='impo' ,tp='bt' ,t=GAP+35+HT_LST ,l= WD_LST-70*2 ,w=70 ,cap=_('&Import') ,props='1' ) # default ,dict(cid='-' ,tp='bt' ,t=GAP+35+HT_LST ,l=GAP+WD_LST-70*1 ,w=70 ,cap=_('Close') ) ]) vals = dict( file=imp_file ,mcrs=(crt, sels) ) btn, \ vals, \ chds = dlg_wrapper(_('Import macros'), GAP+WD_LST+GAP, GAP*4+HT_LST+25*2, cnts, vals, focus_cid='mrcs') if btn is None or btn=='-': return crt,sels= vals['mcrs'] pass; LOG and log('sels={}',sels) if False:pass elif btn=='brow': #ans_s=='file': (new_imp_file ,new_mcrs) = self.dlg_import_choose_mcrs() if new_imp_file is None: continue #while imp_file = new_imp_file mcrs = new_mcrs lmcrs = len(mcrs) crt,sels = '0', ['1'] * lmcrs elif btn=='ch-a': #ans_s=='all': sels = ['1'] * lmcrs elif btn=='ch-n': #ans_s=='no': sels = ['0'] * lmcrs elif btn=='impo': #ans_s=='imp': if '1' not in sels: app.msg_box(_('Select some names'), app.MB_OK) continue (good_nms ,fail_nms) = self.import_from_list([mcr for (ind, mcr) in enumerate(mcrs) if sels[ind]=='1']) l,lt = '\n', '\n ' app.msg_box( _('Import macros:') +lt+lt.join(good_nms) +l+'' +l+_('Skip duplicates:') +lt+lt.join(fail_nms) ,app.MB_OK)
def cancel(self): if not self._is_finished and not self._is_canceled: pass LOG and log('* cancelling building: finished:{}'.format( self._is_finished)) self._is_canceled = True self._stop() cancel_line = _('-- Canceled') self.lines.append(cancel_line) if self.f_can_print(self): output(cancel_line)
def adapt_menu(self,id_menu=0): ''' Add or change top-level menu Macros Param id_menu points to exist menu item (ie by ConfigMenu) for filling ''' pass; LOG and log('id_menu={}',id_menu) PLUG_HINT = '_'+'cuda_macros:adapt_menu' # "_" is sign for ConfigMenu. ":" is subst for "," to avoid call "import ..." if id_menu!=0: # Use this id app.app_proc(app.PROC_MENU_CLEAR, str(id_menu)) else: top_nms = app.app_proc(app.PROC_MENU_ENUM, 'top') if PLUG_HINT in top_nms: # Reuse id from 'top' inf = [inf for inf in top_nms.splitlines() if PLUG_HINT in inf][0] ##?? id_menu = inf.split('|')[2] app.app_proc(app.PROC_MENU_CLEAR, id_menu) else: # Create BEFORE Plugins top_nms = top_nms.splitlines() pass; #LOG and log('top_nms={}',top_nms) if app.app_exe_version() >= '1.0.131': plg_ind = [i for (i,nm) in enumerate(top_nms) if '|plugins' in nm][0] else: # old, pre i18n plg_ind = top_nms.index('&Plugins|') ##?? id_menu = app.app_proc( app.PROC_MENU_ADD, '{};{};{};{}'.format('top', PLUG_HINT, _('&Macros'), plg_ind)) # Fill def hotkeys_desc(cmd_id): hk_s= get_hotkeys_desc(cmd_id) hk_s= '\t\t'+hk_s if hk_s else hk_s return hk_s hk_s = hotkeys_desc( 'cuda_macros,dlg_config') app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, 'cuda_macros,dlg_config',_('&Macros...')+hk_s)) app.app_proc(app.PROC_MENU_ADD, '{};;-'.format( id_menu)) hk_s = hotkeys_desc( cmds.cmd_MacroStart) app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, cmds.cmd_MacroStart, _('&Start record')+hk_s)) hk_s = hotkeys_desc( cmds.cmd_MacroStop) app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, cmds.cmd_MacroStop, _('St&op record')+hk_s)) hk_s = hotkeys_desc( cmds.cmd_MacroCancel) app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, cmds.cmd_MacroCancel, _('&Cancel record')+hk_s)) app.app_proc(app.PROC_MENU_ADD, '{};;-'.format( id_menu)) hk_s = hotkeys_desc( 'cuda_macros,dlg_export') app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, 'cuda_macros,dlg_export',_('&Export...')+hk_s)) hk_s = hotkeys_desc( 'cuda_macros,dlg_import') app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, 'cuda_macros,dlg_import',_('&Import...')+hk_s)) if 0==len(self.macros): return app.app_proc(app.PROC_MENU_ADD, '{};;-'.format( id_menu)) id_sub = app.app_proc(app.PROC_MENU_ADD, '{};{};{}'.format(id_menu, 0, _('&Run'))) for mcr in self.macros: hk_s= hotkeys_desc( f('cuda_macros,run,{}',mcr['id'])) app.app_proc(app.PROC_MENU_ADD, '{};{}{};{}'.format(id_sub, 'cuda_macros,run,' ,mcr['id'], mcr['nm']+hk_s))
def export_to_file(self, exp_file, mcrs): pass; LOG and log('exp_file, mcrs={}',(exp_file, mcrs)) open(exp_file, 'w').write(json.dumps( { 'vers':{ 'ver-mcr':JSON_FORMAT_VER , 'ver-app':app.app_exe_version() , 'ver-api':app.app_api_version() } , 'macros':[{ 'nm': mcr['nm'] , 'evl': mcr['evl'] } for mcr in mcrs] } , indent=4))
def export_to_file(self, exp_file, mcrs): pass LOG and log('exp_file, mcrs={}', (exp_file, mcrs)) open(exp_file, 'w').write( json.dumps( { 'vers': { 'ver-mcr': JSON_FORMAT_VER, 'ver-app': app.app_exe_version(), 'ver-api': app.app_api_version() }, 'macros': [{ 'nm': mcr['nm'], 'evl': mcr['evl'] } for mcr in mcrs] }, indent=4))
def import_from_list(self, mcrs): pass LOG and log('mcrs={}', (mcrs)) good_nms = [] fail_nms = [] ids = [mcr['id'] for mcr in self.macros] my_mcrs = [{'nm': mcr['nm'], 'evl': mcr['evl']} for mcr in self.macros] for mcr in mcrs: if mcr in my_mcrs: fail_nms += [mcr['nm']] continue #for good_nms += [mcr['nm']] id4mcr = random.randint(10000, 99999) while id4mcr in ids: id4mcr = random.randint(10000, 99999) ids += [id4mcr] self.macros += [{'id': id4mcr, 'nm': mcr['nm'], 'evl': mcr['evl']}] if good_nms: self._do_acts() return (good_nms, fail_nms)
def import_from_list(self, mcrs): pass; LOG and log('mcrs={}',(mcrs)) good_nms = [] fail_nms = [] ids = [mcr['id'] for mcr in self.macros] my_mcrs = [{'nm' :mcr['nm'],'evl':mcr['evl']} for mcr in self.macros] for mcr in mcrs: if mcr in my_mcrs: fail_nms += [mcr['nm']] continue #for good_nms += [mcr['nm']] id4mcr = random.randint(10000, 99999) while id4mcr in ids: id4mcr = random.randint(10000, 99999) ids += [id4mcr] self.macros+= [{'id' :id4mcr ,'nm' :mcr['nm'] ,'evl':mcr['evl'] }] if good_nms: self._do_acts() return (good_nms, fail_nms)
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 __init__(self): cmd_nms = [nm for nm in dir(cmds) if nm.startswith('cCommand_') or nm.startswith('cmd_')] cmd_nm2id = {nm:eval('cmds.{}'.format(nm)) for nm in cmd_nms} self.CMD_ID2NM = {str(cmd_id):nm for nm,cmd_id in cmd_nm2id.items()} if len(self.CMD_ID2NM) < len(cmd_nm2id): app.msg_status('Repeated values in cudatext_cmd.py') pass; #LOG and log('cmd_nm2id={}',cmd_nm2id) pass; #LOG and log('CMD_ID2NM={}',self.CMD_ID2NM) ver_macros = apx._json_loads(open(MACROS_JSON).read()) if os.path.exists(MACROS_JSON) else {'ver':JSON_FORMAT_VER, 'list':[]} if ver_macros['ver'] < JSON_FORMAT_VER: # Adapt to new format pass self.tm_ctrl = ver_macros.get('tm_ctrl', {}) self.dlg_prs = ver_macros.get('dlg_prs', {}) self.macros = ver_macros['list'] self.mcr4id = {str(mcr['id']):mcr for mcr in self.macros} self.need_dlg = False self.last_mcr_id= 0 pass; LOG and log('\n\n\nMacros start',)
def dlg_config(self): ''' Show dlg for change macros list. ''' if app.app_api_version() < FROM_API_VERSION: return app.msg_status('Need update CudaText') keys_json = app.app_path(app.APP_DIR_SETTINGS) + os.sep + 'keys.json' keys = apx._json_loads( open(keys_json).read()) if os.path.exists(keys_json) else {} GAP = 5 ids = [mcr['id'] for mcr in self.macros] mcr_ind = ids.index( self.last_mcr_id) if self.last_mcr_id in ids else -1 pass LOG and log('self.last_mcr_id, mcr_ind={}', (self.last_mcr_id, mcr_ind)) times = 1 waits = 5 chngs = '0' endln = '0' while True: (WD_LST, HT_LST) = (self.dlg_prs.get('w_list', 300), self.dlg_prs.get('h_list', 500)) (WD_ACTS, HT_ACTS) = (self.dlg_prs.get('w_acts', 300), self.dlg_prs.get('h_acts', 500)) (WD_BTN, HT_BTN) = (self.dlg_prs.get('w_btn', 150), 24) l_btn = GAP + WD_LST + GAP vw_acts = (WD_ACTS > 0) WD_ACTS = max(0, WD_ACTS) rec_on = ed.get_prop(app.PROP_MACRO_REC) lmcrs = len(self.macros) pass LOG and log('mcr_ind,vw_acts,rec_on={}', (mcr_ind, vw_acts, rec_on)) nmkys = [] for mcr in self.macros: mcr_cid = 'cuda_macros,run,{}'.format(mcr['id']) mcr_keys = keys.get(mcr_cid, {}) kys = '/'.join([ ' * '.join(mcr_keys.get('s1', [])), ' * '.join(mcr_keys.get('s2', [])) ]).strip('/') nmkys += [mcr['nm'] + (' [' + kys + ']' if kys else '')] mcr_acts = '' if vw_acts and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] mcr_acts = '\t'.join(['# ' + nmkys[mcr_ind]] + mcr['evl']) ans = app.dlg_custom( 'Macros', GAP + WD_LST + GAP + WD_BTN + GAP + WD_ACTS + GAP, GAP + HT_LST + GAP, '\n'.join([] + [ C1.join([ 'type=listbox', POS_FMT(l=GAP, t=GAP, r=GAP + WD_LST, b=GAP + HT_LST), 'items=' + '\t'.join(nmkys), 'val=' + str(mcr_ind) # start sel , 'en=' + str(0 if rec_on else 1) # enabled ] # i=0 ) ] + ([ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 1 + HT_BTN * 0, r=l_btn + WD_BTN, b=0), 'cap=&View actions...', 'props=' + str(0 if rec_on or 0 == lmcrs else 1) # default , 'en=' + str(0 if rec_on or 0 == lmcrs else 1) # enabled ] # i=1 ) ] if vw_acts else []) + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 2 + HT_BTN * 1, r=l_btn + WD_BTN, b=0), 'cap=Hot&keys...', 'en=' + str(0 if rec_on or 0 == lmcrs else 1) # enabled ] # i=2 if vw_acts else i=1 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 3 + HT_BTN * 2, r=l_btn + WD_BTN, b=0), 'cap=Re&name...', 'en=' + str(0 if rec_on or 0 == lmcrs else 1) # enabled ] # i=3 if vw_acts else i=2 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 4 + HT_BTN * 3, r=l_btn + WD_BTN, b=0), 'cap=&Delete...', 'en=' + str(0 if rec_on or 0 == lmcrs else 1) # enabled ] # i=4 if vw_acts else i=3 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 6 + HT_BTN * 5, r=l_btn + WD_BTN, b=0), 'cap=&Run!', 'props=' + str(1 if not vw_acts and not rec_on else 0) # default , 'en=' + str(0 if rec_on or 0 == lmcrs else 1) # enabled ] # i=5 if vw_acts else i=4 ) ] + [ C1.join([ 'type=label', POS_FMT(l=l_btn, t=GAP * 7 + HT_BTN * 6 + 3, r=l_btn + int(WD_BTN / 3), b=0), 'cap=&Times' ] # i=6 if vw_acts else i=5 ) ] + [ C1.join([ 'type=spinedit', POS_FMT(l=l_btn + int(WD_BTN / 3) + GAP, t=GAP * 7 + HT_BTN * 6, r=l_btn + WD_BTN, b=0), 'val=' + str(times), 'props=0,{},1'.format(self.dlg_prs.get('times', 1000)), 'en=' + str(0 if rec_on else 1) # enabled ] # i=7 if vw_acts else i=6 ) ] + [ C1.join([ 'type=label', POS_FMT(l=l_btn, t=GAP * 8 + HT_BTN * 7 + 3, r=l_btn + int(WD_BTN / 3), b=0), 'cap=&Wait' ] # i=8 if vw_acts else i=7 ) ] + [ C1.join([ 'type=spinedit', POS_FMT(l=l_btn + int(WD_BTN / 3) + GAP, t=GAP * 8 + HT_BTN * 7, r=l_btn + WD_BTN - 40, b=0), 'val=' + str(waits), 'props=1,3600,1', 'en=' + str(0 if rec_on else 1) # enabled ] # i=9 if vw_acts else i=8 ) ] + [ C1.join([ 'type=label', POS_FMT(l=l_btn + WD_BTN - 40 + GAP, t=GAP * 8 + HT_BTN * 7 + 3, r=l_btn + WD_BTN, b=0), 'cap=sec' ] # i=10 if vw_acts else i=9 ) ] + [ C1.join([ 'type=check', POS_FMT(l=l_btn, t=GAP * 9 + HT_BTN * 8, r=l_btn + WD_BTN, b=0), 'cap=While text c&hanges', 'val=' + chngs ] # i=11 if vw_acts else i=10 ) ] + [ C1.join([ 'type=check', POS_FMT(l=l_btn, t=GAP * 10 + HT_BTN * 9, r=l_btn + WD_BTN, b=0), 'cap=Until c&aret on last line', 'val=' + endln ] # i=12 if vw_acts else i=11 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 12 + HT_BTN * 11, r=l_btn + WD_BTN, b=0), 'cap={}'.format( '&Stop record' if rec_on else '&Start record'), 'props=' + str(1 if rec_on or 0 == lmcrs else 0) # default ] # i=13 if vw_acts else i=12 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP * 13 + HT_BTN * 12, r=l_btn + WD_BTN, b=0), 'cap=Canc&el record', 'en=' + str(1 if rec_on else 0) # enabled ] # i=14 if vw_acts else i=13 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=HT_LST - HT_BTN * 2, r=l_btn + WD_BTN, b=0), 'cap=C&ustom...', 'en=' + str(0 if rec_on else 1) # enabled ] # i=15 if vw_acts else i=14 ) ] + [ C1.join([ 'type=button', POS_FMT(l=l_btn, t=GAP + HT_LST - HT_BTN * 1, r=l_btn + WD_BTN, b=0), 'cap=&Close' ] # i=16 if vw_acts else i=15 ) ] + ([ C1.join([ 'type=memo', POS_FMT(l=GAP + WD_LST + GAP + WD_BTN + GAP, t=GAP, r=GAP + WD_LST + GAP + WD_BTN + GAP + WD_ACTS, b=GAP + HT_ACTS), 'val=' + mcr_acts, 'props=1,1,1' # ro,mono,border ] # i=17 ) ] if vw_acts else [])), apx.icase( vw_acts and not rec_on, 0 # View , not vw_acts and not rec_on, 0 # View , vw_acts and rec_on, 11, not vw_acts and rec_on, 10)) # start focus pass LOG and log('ans={}', ans) if ans is None: break #while (ans_i, vals) = ans ans_s = apx.icase( False, '', vw_acts and ans_i == 1, 'view', vw_acts and ans_i == 2, 'hotkeys', not vw_acts and ans_i == 1, 'hotkeys', vw_acts and ans_i == 3, 'rename', not vw_acts and ans_i == 2, 'rename', vw_acts and ans_i == 4, 'delete', not vw_acts and ans_i == 3, 'delete', vw_acts and ans_i == 5, 'run', not vw_acts and ans_i == 4, 'run', vw_acts and ans_i == 12, 'rec', not vw_acts and ans_i == 7, 'rec', vw_acts and ans_i == 14, 'cancel', not vw_acts and ans_i == 13, 'cancel', vw_acts and ans_i == 15, 'custom', not vw_acts and ans_i == 14, 'custom', vw_acts and ans_i == 16, 'close', not vw_acts and ans_i == 15, 'close', '?') mcr_ind = int(vals.splitlines()[0]) times = int(vals.splitlines()[7 if vw_acts else 6]) waits = int(vals.splitlines()[9 if vw_acts else 8]) chngs = vals.splitlines()[11 if vw_acts else 10] endln = vals.splitlines()[12 if vw_acts else 11] pass LOG and log('mcr_ind,times,waits,chngs,endln={}', (mcr_ind, times, waits, chngs, endln)) if 0 != lmcrs and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] self.last_mcr_id = mcr['id'] if ans_s == 'close': break #while if ans_s == 'custom': #Custom custs = app.dlg_input_ex( 5, 'Custom dialog Macros', 'Height of macro list (min 450)', str(self.dlg_prs.get('h_list', 400)), 'Width of macro list (min 200)', str(self.dlg_prs.get('w_list', 500)), 'Width of action list (min 200, <=0-hide)', str(self.dlg_prs.get('w_acts', 500)), 'Width of buttons (min 150)', str(self.dlg_prs.get('w_btn', 150)), 'Max run times (min 100)', str(self.dlg_prs.get('times', 1000))) if custs is not None: self.dlg_prs['h_list'] = max(450, int(custs[0])) self.dlg_prs['h_acts'] = self.dlg_prs['h_list'] self.dlg_prs['w_list'] = max(200, int(custs[1])) self.dlg_prs['w_acts'] = max(200, int( custs[2])) if int(custs[2]) > 0 else int(custs[2]) self.dlg_prs['w_btn'] = max(150, int(custs[3])) self.dlg_prs['times'] = max(100, int(custs[4])) open(MACROS_JSON, 'w').write( json.dumps( { 'ver': JSON_FORMAT_VER, 'list': self.macros, 'dlg_prs': self.dlg_prs }, indent=4)) continue #while if mcr_ind not in range(lmcrs): app.msg_box('Select macro', app.MB_OK) continue #while what = '' changed = False if False: pass elif ans_s == 'view': #View continue #while elif ans_s == 'rename': #Rename mcr_nm = app.dlg_input( 'New name for: {}'.format(nmkys[mcr_ind]), mcr['nm']) if mcr_nm is None or mcr_nm == mcr['nm']: continue #while while mcr_nm in [mcr['nm'] for mcr in self.macros]: app.msg_box( 'Select other name.\nMacro names now are:\n\n' + '\n'.join(nmkys), app.MB_OK) mcr_nm = app.dlg_input( 'New name for: {}'.format(nmkys[mcr_ind]), mcr_nm) if mcr_nm is None or mcr_nm == mcr['nm']: break #while mcr_nm if mcr_nm is None or mcr_nm == mcr['nm']: continue #while what = 'rename' mcr['nm'] = mcr_nm changed = True elif ans_s == 'delete': #Del if app.msg_box('Delete macro\n {}'.format(nmkys[mcr_ind]), app.MB_YESNO) != app.ID_YES: continue #while what = 'delete:' + str(mcr['id']) del self.macros[mcr_ind] mcr_ind = min(mcr_ind, len(self.macros) - 1) changed = True elif ans_s == 'hotkeys': #Hotkeys app.dlg_hotkeys('cuda_macros,run,' + str(mcr['id'])) keys = apx._json_loads(open( keys_json).read()) if os.path.exists(keys_json) else {} changed = True elif ans_s == 'run': #Run if (times == 0 and waits == 0 and chngs == '0' and endln == '0'): app.msg_box('Select stop condition', app.MB_OK) continue self.run(mcr['id'], max(0, times), max(0, waits), chngs == '1', endln == '1') return elif ans_s == 'rec' and not rec_on: #Start record return ed.cmd(cmds.cmd_MacroStart) elif ans_s == 'rec' and rec_on: #Stop record self.need_dlg = True return ed.cmd( cmds.cmd_MacroStop ) # Return for clear rec-mode in StatusBar, will recall from on_macro elif ans_s == 'cancel' and rec_on: #Cancel record return ed.cmd(cmds.cmd_MacroCancel ) # Return for clear rec-mode in StatusBar if changed: self._do_acts(what)
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 _record_data_to_cmds(self, rec_data): ''' Coverting from record data to list of API command Param rec_data "\n"-separated list of number number,string py:string_module,string_method,string_param ''' # Native converting evls = [] rcs = rec_data.splitlines() for rc in rcs: if False: pass elif rc[0] in '0123456789': if rc in self.CMD_ID2NM: # For ed.cmd(id) evls += ['ed.cmd(cmds.{})'.format(self.CMD_ID2NM[rc])] continue #for rc if ',' in rc: (id_cmd, tx_cmd) = rc[0:rc.index(',')], rc[1 + rc.index(','):] if '' == id_cmd.strip( '0123456789') and id_cmd in self.CMD_ID2NM: # For ed.cmd(id, text) evls += [ "ed.cmd(cmds.{},{})".format( self.CMD_ID2NM[id_cmd], repr(tx_cmd)) ] continue #for rc elif rc.startswith('py:cuda_macros,'): # Skip macro-tools continue #for rc elif rc[0:3] == 'py:': # Plugin cmd evls += [ "app.app_proc(app.PROC_EXEC_PLUGIN, '{}')".format(rc[3:]) ] continue #for rc pass LOG and log('unknown rec-item: {}', rc) # return evls # Optimization # (1) ed.cmd(cmds.cCommand_TextInsert,'A') # ed.cmd(cmds.cCommand_TextInsert,'B') # convert to # ed.cmd(cmds.cCommand_TextInsert,'AB') has_TI = 1 < len( [evl for evl in evls if 'cmds.cCommand_TextInsert,' in evl]) if has_TI: reTI2 = re.compile(r"ed.cmd\(cmds.cCommand_TextInsert,'(.+)'\)" + C1 + r"ed.cmd\(cmds.cCommand_TextInsert,'(.+)'\)") evls_c1 = C1.join(evls) (evls_c1, rpls) = reTI2.subn(r"ed.cmd(cmds.cCommand_TextInsert,'\1\2')", evls_c1) while 0 < rpls: (evls_c1, rpls) = reTI2.subn(r"ed.cmd(cmds.cCommand_TextInsert,'\1\2')", evls_c1) evls = evls_c1.split(C1) #if has_TI pass LOG and log('evls={}', evls) return evls
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 dlg_import(self): ''' Show dlg for import some macros. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status('Need update CudaText') (imp_file ,mcrs) = self.dlg_import_choose_mcrs() if imp_file is None: return lmcrs = len(mcrs) GAP = 5 (WD_LST ,HT_LST)= (500 ,500) crt,sels= '0', ['1'] * lmcrs while True: ans = app.dlg_custom('Import macros' ,GAP+WD_LST+GAP, GAP*5+HT_LST+25*2, '\n'.join([] +[C1.join(['type=label' ,POS_FMT(l=GAP, t=GAP+3, r=GAP+85, b=0) ,'cap=Import &from' ] # i=0 )] +[C1.join(['type=edit' ,POS_FMT(l=GAP+85, t=GAP, r=GAP+WD_LST-35,b=0) ,'val={}'.format(imp_file) ] # i=1 )] +[C1.join(['type=button' ,POS_FMT(l=GAP+HT_LST-35, t=GAP-2, r=GAP+WD_LST, b=0) ,'cap=&...' ] # i=2 )] +[C1.join(['type=checklistbox' ,POS_FMT(l=GAP, t=GAP*2+30, r=GAP+WD_LST, b=GAP+25+HT_LST) ,'items=' +'\t'.join([mcr['nm'] for mcr in mcrs]) ,'val=' + crt+';'+','.join(sels) ] # i=3 )] +[C1.join(['type=button' ,POS_FMT(l=GAP*1, t=GAP*3+25+HT_LST, r=GAP*1+80*1, b=0) ,'cap=Check &all' ] # i=4 )] +[C1.join(['type=button' ,POS_FMT(l=GAP*2+80, t=GAP*3+25+HT_LST, r=GAP*2+80*2, b=0) ,'cap=U&ncheck all' ] # i=5 )] +[C1.join(['type=button' ,POS_FMT(l= WD_LST-60*2, t=GAP*3+25+HT_LST, r= WD_LST-60*1, b=0) ,'cap=&Import' ] # i=6 )] +[C1.join(['type=button' ,POS_FMT(l=GAP+WD_LST-60*1, t=GAP*3+25+HT_LST, r=GAP+WD_LST-60*0, b=0) ,'cap=&Close' ] # i=7 )] ), 3) # start focus pass; LOG and log('ans={}',ans) if ans is None: break #while (ans_i ,vals) = ans ans_s = apx.icase(False,'' ,ans_i==2, 'file' ,ans_i==4, 'all' ,ans_i==5, 'no' ,ans_i==6, 'imp' ,ans_i==7, 'close' ) if ans_s=='close': break #while v_3 = vals.splitlines()[3] crt,sels= v_3.split(';') sels = sels.strip(',').split(',') pass; LOG and log('sels={}',sels) if False:pass elif ans_s=='file': (new_imp_file ,new_mcrs) = self.dlg_import_choose_mcrs() if new_imp_file is None: continue #while imp_file = new_imp_file mcrs = new_mcrs lmcrs = len(mcrs) crt,sels = '0', ['1'] * lmcrs elif ans_s=='all': sels = ['1'] * lmcrs elif ans_s=='no': sels = ['0'] * lmcrs elif ans_s=='imp': if '1' not in sels: app.msg_box('Select some names', app.MB_OK) continue (good_nms ,fail_nms) = self.import_from_list([mcr for (ind, mcr) in enumerate(mcrs) if sels[ind]=='1']) l,lt = '\n', '\n ' app.msg_box( 'Import macros:' +lt+lt.join(good_nms) +l+'' +l+'Skip duplicates:' +lt+lt.join(fail_nms) ,app.MB_OK)
def on_macro(self, ed_self, mcr_record): ''' Finish for macro-recording. Params mcr_record "\n"-separated list of number number,string py:string_module,string_method,string_param ''' pass LOG and log('mcr_record={}', mcr_record) if '' == mcr_record: return app.msg_status('Empty record') def_nm = '' nms = [mcr['nm'] for mcr in self.macros] for num in range(1, 1000): def_nm = 'Macro{}'.format(num) if def_nm not in nms: break #for num while True: mcr_nm = app.dlg_input( 'Macro name. Tricks: "!NM" overwrite NM, "=NM" show NM in dialog', def_nm) if mcr_nm is None: return mcr_nm = mcr_nm.strip() if '' == mcr_nm: continue #while if mcr_nm[0] == '=': self.need_dlg = True mcr_nm = mcr_nm[1:] use_old = False if '' == mcr_nm: continue #while if mcr_nm[0] == '!': use_old = True mcr_nm = mcr_nm[1:] if '' != mcr_nm: break #while pass LOG and log('self.need_dlg, use_old, mcr_nm={}', (self.need_dlg, use_old, mcr_nm)) if use_old and mcr_nm in nms: mcr_ind = nms.index(mcr_nm) self.macros[mcr_ind]['rec'] = mcr_record self.macros[mcr_ind]['evl'] = self._record_data_to_cmds(mcr_record) id4mcr = self.macros[mcr_ind]['id'] else: while mcr_nm in nms: app.msg_box( 'Select other name.\nMacros names now:\n\n' + '\n'.join(nms), app.MB_OK) mcr_nm = app.dlg_input('Macro name', mcr_nm) if mcr_nm is None: return id4mcr = random.randint(10000, 99999) while id4mcr in self.mcr4id: id4mcr = random.randint(10000, 99999) self.macros += [{ 'id': id4mcr ##?? conflicts? , 'nm': mcr_nm, 'rec': mcr_record, 'evl': self._record_data_to_cmds(mcr_record) }] self._do_acts() if self.need_dlg: self.need_dlg = False self.last_mcr_id = id4mcr self.dlg_config()
def dlg_config(self): ''' Show dlg for change macros list. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status(_('Need update CudaText')) keys_json = app.app_path(app.APP_DIR_SETTINGS)+os.sep+'keys.json' keys = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {} ids = [mcr['id'] for mcr in self.macros] mcr_ind = ids.index(self.last_mcr_id) if self.last_mcr_id in ids else -1 pass; LOG and log('self.last_mcr_id, mcr_ind={}',(self.last_mcr_id,mcr_ind)) times = 1 waits = 5 chngs = '0' endln = '0' while True: WD_LST, \ HT_LST = (self.dlg_prs.get('w_list', 300) ,self.dlg_prs.get('h_list', 500)) WD_ACTS,\ HT_ACTS = (self.dlg_prs.get('w_acts', 300) ,self.dlg_prs.get('h_acts', 500)) WD_BTN, \ HT_BTN = (self.dlg_prs.get('w_btn', 150), 24) WD_BTN_3= int(WD_BTN/3) l_btn = GAP+WD_LST+GAP l_acts = GAP+WD_LST+GAP+WD_BTN+GAP vw_acts = (WD_ACTS>0) WD_ACTS = max(0, WD_ACTS) rec_on = ed.get_prop(app.PROP_MACRO_REC) lmcrs = len(self.macros) pass; LOG and log('mcr_ind,vw_acts,rec_on={}',(mcr_ind,vw_acts,rec_on)) nmkys = [] for mcr in self.macros: mcr_cid = 'cuda_macros,run,{}'.format(mcr['id']) mcr_keys= keys.get(mcr_cid, {}) kys = '/'.join([' * '.join(mcr_keys.get('s1', [])) ,' * '.join(mcr_keys.get('s2', [])) ]).strip('/') nmkys += [mcr['nm'] + (' ['+kys+']' if kys else '')] mcr_acts= [''] # mcr_acts= '' if vw_acts and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] mcr_acts= ['# '+nmkys[mcr_ind]] + mcr['evl'] # mcr_acts= '\t'.join(['# '+nmkys[mcr_ind]] + mcr['evl']) def_stst = '1' if rec_on or 0==lmcrs else '0' n_edable = '0' if rec_on or 0==lmcrs else '1' n_vwable = '1' if not vw_acts and not rec_on else '0' only_rec_off= '0' if rec_on else '1' only_rec_on = '1' if rec_on else '0' tims_props = '0,{},1'.format(self.dlg_prs.get('times', 1000)) stst_cap = _('&Stop record') if rec_on else _('&Start record') cnts = ([] +[dict(cid='mrcs' ,tp='lbx' ,t=GAP ,h=HT_LST ,l=GAP ,w=WD_LST ,items=nmkys ,en=only_rec_off )] +( [dict(cid='view' ,tp='bt' ,t=GAP* 1+HT_BTN* 0 ,l=l_btn ,w=WD_BTN ,cap=_('&View actions') ,props=n_edable,en=n_edable )] # default if vw_acts else []) +[dict(cid='keys' ,tp='bt' ,t=GAP* 2+HT_BTN* 1 ,l=l_btn ,w=WD_BTN ,cap=_('Hot&keys...') ,en=n_edable )] +[dict(cid='renm' ,tp='bt' ,t=GAP* 3+HT_BTN* 2 ,l=l_btn ,w=WD_BTN ,cap=_('Re&name...') ,en=n_edable )] +[dict(cid='del' ,tp='bt' ,t=GAP* 4+HT_BTN* 3 ,l=l_btn ,w=WD_BTN ,cap=_('&Delete...') ,en=n_edable )] +[dict(cid='run' ,tp='bt' ,t=GAP* 6+HT_BTN* 5 ,l=l_btn ,w=WD_BTN ,cap=_('&Run!') ,props=n_vwable ,en=n_edable )] # default +[dict( tp='lb' ,tid='times' ,l=l_btn ,w=WD_BTN_3 ,cap=_('&Times') )] +[dict(cid='times' ,tp='sp-ed',t=GAP* 7+HT_BTN* 6 ,l=l_btn+WD_BTN_3+GAP ,r=l_btn+WD_BTN ,props=tims_props,en=only_rec_off )] # min,max,step +[dict( tp='lb' ,tid='waits' ,l=l_btn ,w=WD_BTN_3 ,cap=_('&Wait') )] +[dict(cid='waits' ,tp='sp-ed',t=GAP* 8+HT_BTN* 7 ,l=l_btn+WD_BTN_3+GAP ,r=l_btn+WD_BTN-40 ,props='1,3600,1',en=only_rec_off )] # min,max,step +[dict( tp='lb' ,tid='waits' ,l=l_btn+WD_BTN-40+GAP ,w=WD_BTN ,cap=_('sec') )] +[dict(cid='chngs' ,tp='ch' ,t=GAP* 9+HT_BTN* 8 ,l=l_btn ,w=WD_BTN ,cap=_('While text c&hanges') )] +[dict(cid='endln' ,tp='ch' ,t=GAP*10+HT_BTN* 9 ,l=l_btn ,w=WD_BTN ,cap=_('Until c&aret on last line') )] +[dict(cid='stst' ,tp='bt' ,t=GAP*12+HT_BTN*11 ,l=l_btn ,w=WD_BTN ,cap=stst_cap ,props=def_stst )] +[dict(cid='canc' ,tp='bt' ,t=GAP*13+HT_BTN*12 ,l=l_btn ,w=WD_BTN ,cap=_('Canc&el record') ,en=only_rec_on )] +[dict(cid='adju' ,tp='bt' ,t= HT_LST-HT_BTN*2 ,l=l_btn ,w=WD_BTN ,cap=_('Ad&just...') ,en=only_rec_off )] +[dict(cid='-' ,tp='bt' ,t=GAP+HT_LST-HT_BTN*1 ,l=l_btn ,w=WD_BTN ,cap=_('Close') )] +( [dict(cid='acts' ,tp='me' ,t=GAP ,h=HT_ACTS ,l=l_acts ,w=WD_ACTS ,props='1,1,1' )] # ro,mono,border if vw_acts else []) ) vals = dict( mrcs=mcr_ind ,times=times ,waits=waits ,chngs=chngs ,endln=endln ) if vw_acts: vals.update( dict( acts=mcr_acts )) btn, \ vals, \ chds = dlg_wrapper(_('Macros'), GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS+GAP,GAP+HT_LST+GAP, cnts, vals, focus_cid='mrcs') if btn is None or btn=='-': return mcr_ind = vals['mrcs'] times = vals['times'] waits = vals['waits'] chngs = vals['chngs'] endln = vals['endln'] pass; LOG and log('mcr_ind,times,waits,chngs,endln={}',(mcr_ind,times,waits,chngs,endln)) if 0!=lmcrs and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] self.last_mcr_id = mcr['id'] # if ans_s=='close': break #while if btn=='adju': #ans_s=='custom': #Custom custs = app.dlg_input_ex(5, _('Custom dialog Macros') , _('Height of macro list (min 450)') , str(self.dlg_prs.get('h_list', 400)) , _('Width of macro list (min 200)') , str(self.dlg_prs.get('w_list', 500)) , _('Width of action list (min 200, <=0-hide)'), str(self.dlg_prs.get('w_acts', 500)) , _('Width of buttons (min 150)') , str(self.dlg_prs.get('w_btn', 150)) , _('Max run times (min 100)') , str(self.dlg_prs.get('times', 1000)) ) if custs is not None: self.dlg_prs['h_list'] = max(450, int(custs[0])); self.dlg_prs['h_acts'] = self.dlg_prs['h_list'] self.dlg_prs['w_list'] = max(200, int(custs[1])) self.dlg_prs['w_acts'] = max(200, int(custs[2])) if int(custs[2])>0 else int(custs[2]) self.dlg_prs['w_btn'] = max(150, int(custs[3])) self.dlg_prs['times'] = max(100, int(custs[4])) open(MACROS_JSON, 'w').write(json.dumps({'ver':JSON_FORMAT_VER, 'list':self.macros, 'dlg_prs':self.dlg_prs}, indent=4)) continue #while if mcr_ind not in range(lmcrs): app.msg_box(_('Select macro'), app.MB_OK) continue #while what = '' changed = False if False:pass elif btn=='view': #ans_s=='view': #View continue #while elif btn=='renm': #ans_s=='rename': #Rename mcr_nm = app.dlg_input(_('New name for: {}').format(nmkys[mcr_ind]) ,mcr['nm']) if mcr_nm is None or mcr_nm==mcr['nm']: continue #while while mcr_nm in [mcr['nm'] for mcr in self.macros]: app.msg_box(_('Select other name.\nMacro names now are:\n\n')+'\n'.join(nmkys), app.MB_OK) mcr_nm = app.dlg_input(_('New name for: {}').format(nmkys[mcr_ind]) ,mcr_nm) if mcr_nm is None or mcr_nm==mcr['nm']: break #while mcr_nm if mcr_nm is None or mcr_nm==mcr['nm']: continue #while what = 'rename' mcr['nm'] = mcr_nm changed = True elif btn=='del': #ans_s=='delete': #Del if app.msg_box( _('Delete macro\n {}').format(nmkys[mcr_ind]) , app.MB_YESNO)!=app.ID_YES: continue #while what = 'delete:'+str(mcr['id']) del self.macros[mcr_ind] mcr_ind = min(mcr_ind, len(self.macros)-1) changed = True elif btn=='keys': #ans_s=='hotkeys': #Hotkeys app.dlg_hotkeys('cuda_macros,run,'+str(mcr['id'])) keys = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {} changed = True elif btn=='run': #ans_s=='run': #Run if (times==0 and waits==0 and chngs=='0' and endln=='0'): app.msg_box(_('Select stop condition'), app.MB_OK) continue self.run(mcr['id'], max(0, times), max(0, waits), chngs=='1', endln=='1') return elif btn=='stst' and not rec_on: #Start record # elif ans_s=='rec' and not rec_on: #Start record return ed.cmd(cmds.cmd_MacroStart) elif btn=='stst' and rec_on: #Stop record # elif ans_s=='rec' and rec_on: #Stop record self.need_dlg = True return ed.cmd(cmds.cmd_MacroStop) # Return for clear rec-mode in StatusBar, will recall from on_macro elif btn=='canc' and rec_on: #Cancel record # elif ans_s=='cancel' and rec_on: #Cancel record return ed.cmd(cmds.cmd_MacroCancel) # Return for clear rec-mode in StatusBar if changed: self._do_acts(what)
def dlg_export(self): ''' Show dlg for export some macros. ''' if app.app_api_version() < FROM_API_VERSION: return app.msg_status('Need update CudaText') if 0 == len(self.macros): return app.msg_status('No macros for export') exp_file = app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') exp_file = '' if exp_file is None else exp_file exp_file = exp_file + ('' if '' == exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') (WD_LST, HT_LST) = (500, 500) lmcrs = len(self.macros) crt, sels = '0', ['0'] * lmcrs while True: pass LOG and log('sels={}', sels) ans = app.dlg_custom( 'Export macros', GAP + WD_LST + GAP, GAP * 5 + HT_LST + 25 * 2, '\n'.join([] + [ C1.join([ 'type=label', POS_FMT(l=GAP, t=GAP + 3, r=GAP + 70, b=0), 'cap=Export &to' ] # i=0 ) ] + [ C1.join([ 'type=edit', POS_FMT(l=GAP + 70, t=GAP, r=GAP + WD_LST - 35, b=0), 'val={}'.format(exp_file) ] # i=1 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP + HT_LST - 35, t=GAP - 2, r=GAP + WD_LST, b=0), 'cap=&...' ] # i=2 ) ] + [ C1.join([ 'type=checklistbox', POS_FMT(l=GAP, t=GAP * 2 + 30, r=GAP + WD_LST, b=GAP + 25 + HT_LST), 'items=' + '\t'.join([mcr['nm'] for mcr in self.macros]), 'val=' + crt + ';' + ','.join(sels) ] # i=3 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP * 1, t=GAP * 3 + 25 + HT_LST, r=GAP * 1 + 80 * 1, b=0), 'cap=Check &all' ] # i=4 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP * 2 + 80, t=GAP * 3 + 25 + HT_LST, r=GAP * 2 + 80 * 2, b=0), 'cap=U&ncheck all' ] # i=5 ) ] + [ C1.join([ 'type=button', POS_FMT(l=WD_LST - 60 * 2, t=GAP * 3 + 25 + HT_LST, r=WD_LST - 60 * 1, b=0), 'cap=&Export' ] # i=6 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP + WD_LST - 60 * 1, t=GAP * 3 + 25 + HT_LST, r=GAP + WD_LST - 60 * 0, b=0), 'cap=&Close' ] # i=7 ) ]), 3) # start focus pass LOG and log('ans={}', ans) if ans is None: break #while (ans_i, vals) = ans ans_s = apx.icase(False, '', ans_i == 2, 'file', ans_i == 4, 'all', ans_i == 5, 'no', ans_i == 6, 'exp', ans_i == 7, 'close') if ans_s == 'close': break #while v_3 = vals.splitlines()[3] crt, sels = v_3.split(';') sels = sels.strip(',').split(',') pass LOG and log('sels={}', sels) if False: pass elif ans_s == 'file': new_exp_file = app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') if new_exp_file is not None: exp_file = new_exp_file exp_file = exp_file + ('' if '' == exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') elif ans_s == 'all': sels = ['1'] * lmcrs elif ans_s == 'no': sels = ['0'] * lmcrs elif ans_s == 'exp': if '1' not in sels: app.msg_box('Select some names', app.MB_OK) continue self.export_to_file(exp_file, [ mcr for (ind, mcr) in enumerate(self.macros) if sels[ind] == '1' ]) return
def dlg_export(self): ''' Show dlg for export some macros. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status('Need update CudaText') if 0==len(self.macros): return app.msg_status('No macros for export') exp_file= app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') exp_file= '' if exp_file is None else exp_file exp_file= exp_file+('' if ''==exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') (WD_LST ,HT_LST)= (500 ,500) lmcrs = len(self.macros) crt,sels= '0', ['0'] * lmcrs while True: pass; LOG and log('sels={}',sels) ans = app.dlg_custom('Export macros' ,GAP+WD_LST+GAP, GAP*5+HT_LST+25*2, '\n'.join([] +[C1.join(['type=label' ,POS_FMT(l=GAP, t=GAP+3, r=GAP+70, b=0) ,'cap=Export &to' ] # i=0 )] +[C1.join(['type=edit' ,POS_FMT(l=GAP+70, t=GAP, r=GAP+WD_LST-35,b=0) ,'val={}'.format(exp_file) ] # i=1 )] +[C1.join(['type=button' ,POS_FMT(l=GAP+HT_LST-35, t=GAP-2, r=GAP+WD_LST, b=0) ,'cap=&...' ] # i=2 )] +[C1.join(['type=checklistbox' ,POS_FMT(l=GAP, t=GAP*2+30, r=GAP+WD_LST, b=GAP+25+HT_LST) ,'items=' +'\t'.join([mcr['nm'] for mcr in self.macros]) ,'val=' + crt+';'+','.join(sels) ] # i=3 )] +[C1.join(['type=button' ,POS_FMT(l=GAP*1, t=GAP*3+25+HT_LST, r=GAP*1+80*1, b=0) ,'cap=Check &all' ] # i=4 )] +[C1.join(['type=button' ,POS_FMT(l=GAP*2+80, t=GAP*3+25+HT_LST, r=GAP*2+80*2, b=0) ,'cap=U&ncheck all' ] # i=5 )] +[C1.join(['type=button' ,POS_FMT(l= WD_LST-60*2, t=GAP*3+25+HT_LST, r= WD_LST-60*1, b=0) ,'cap=&Export' ] # i=6 )] +[C1.join(['type=button' ,POS_FMT(l=GAP+WD_LST-60*1, t=GAP*3+25+HT_LST, r=GAP+WD_LST-60*0, b=0) ,'cap=&Close' ] # i=7 )] ), 3) # start focus pass; LOG and log('ans={}',ans) if ans is None: break #while (ans_i ,vals) = ans ans_s = apx.icase(False,'' ,ans_i==2, 'file' ,ans_i==4, 'all' ,ans_i==5, 'no' ,ans_i==6, 'exp' ,ans_i==7, 'close' ) if ans_s=='close': break #while v_3 = vals.splitlines()[3] crt,sels= v_3.split(';') sels = sels.strip(',').split(',') pass; LOG and log('sels={}',sels) if False:pass elif ans_s=='file': new_exp_file= app.dlg_file(False, '', '', 'Cuda macros|*.cuda-macros') if new_exp_file is not None: exp_file = new_exp_file exp_file = exp_file+('' if ''==exp_file or exp_file.endswith('.cuda-macros') else '.cuda-macros') elif ans_s=='all': sels = ['1'] * lmcrs elif ans_s=='no': sels = ['0'] * lmcrs elif ans_s=='exp': if '1' not in sels: app.msg_box('Select some names', app.MB_OK) continue self.export_to_file(exp_file, [mcr for (ind, mcr) in enumerate(self.macros) if sels[ind]=='1']) return
def dlg_import(self): ''' Show dlg for import some macros. ''' if app.app_api_version() < FROM_API_VERSION: return app.msg_status('Need update CudaText') (imp_file, mcrs) = self.dlg_import_choose_mcrs() if imp_file is None: return lmcrs = len(mcrs) GAP = 5 (WD_LST, HT_LST) = (500, 500) crt, sels = '0', ['1'] * lmcrs while True: ans = app.dlg_custom( 'Import macros', GAP + WD_LST + GAP, GAP * 5 + HT_LST + 25 * 2, '\n'.join([] + [ C1.join([ 'type=label', POS_FMT(l=GAP, t=GAP + 3, r=GAP + 85, b=0), 'cap=Import &from' ] # i=0 ) ] + [ C1.join([ 'type=edit', POS_FMT(l=GAP + 85, t=GAP, r=GAP + WD_LST - 35, b=0), 'val={}'.format(imp_file) ] # i=1 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP + HT_LST - 35, t=GAP - 2, r=GAP + WD_LST, b=0), 'cap=&...' ] # i=2 ) ] + [ C1.join([ 'type=checklistbox', POS_FMT(l=GAP, t=GAP * 2 + 30, r=GAP + WD_LST, b=GAP + 25 + HT_LST), 'items=' + '\t'.join([mcr['nm'] for mcr in mcrs]), 'val=' + crt + ';' + ','.join(sels) ] # i=3 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP * 1, t=GAP * 3 + 25 + HT_LST, r=GAP * 1 + 80 * 1, b=0), 'cap=Check &all' ] # i=4 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP * 2 + 80, t=GAP * 3 + 25 + HT_LST, r=GAP * 2 + 80 * 2, b=0), 'cap=U&ncheck all' ] # i=5 ) ] + [ C1.join([ 'type=button', POS_FMT(l=WD_LST - 60 * 2, t=GAP * 3 + 25 + HT_LST, r=WD_LST - 60 * 1, b=0), 'cap=&Import' ] # i=6 ) ] + [ C1.join([ 'type=button', POS_FMT(l=GAP + WD_LST - 60 * 1, t=GAP * 3 + 25 + HT_LST, r=GAP + WD_LST - 60 * 0, b=0), 'cap=&Close' ] # i=7 ) ]), 3) # start focus pass LOG and log('ans={}', ans) if ans is None: break #while (ans_i, vals) = ans ans_s = apx.icase(False, '', ans_i == 2, 'file', ans_i == 4, 'all', ans_i == 5, 'no', ans_i == 6, 'imp', ans_i == 7, 'close') if ans_s == 'close': break #while v_3 = vals.splitlines()[3] crt, sels = v_3.split(';') sels = sels.strip(',').split(',') pass LOG and log('sels={}', sels) if False: pass elif ans_s == 'file': (new_imp_file, new_mcrs) = self.dlg_import_choose_mcrs() if new_imp_file is None: continue #while imp_file = new_imp_file mcrs = new_mcrs lmcrs = len(mcrs) crt, sels = '0', ['1'] * lmcrs elif ans_s == 'all': sels = ['1'] * lmcrs elif ans_s == 'no': sels = ['0'] * lmcrs elif ans_s == 'imp': if '1' not in sels: app.msg_box('Select some names', app.MB_OK) continue (good_nms, fail_nms) = self.import_from_list([ mcr for (ind, mcr) in enumerate(mcrs) if sels[ind] == '1' ]) l, lt = '\n', '\n ' app.msg_box( 'Import macros:' + lt + lt.join(good_nms) + l + '' + l + 'Skip duplicates:' + lt + lt.join(fail_nms), app.MB_OK)
def dlg_config(self): ''' Show dlg for change macros list. ''' if app.app_api_version()<FROM_API_VERSION: return app.msg_status('Need update CudaText') keys_json = app.app_path(app.APP_DIR_SETTINGS)+os.sep+'keys.json' keys = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {} GAP = 5 ids = [mcr['id'] for mcr in self.macros] mcr_ind = ids.index(self.last_mcr_id) if self.last_mcr_id in ids else -1 pass; LOG and log('self.last_mcr_id, mcr_ind={}',(self.last_mcr_id,mcr_ind)) times = 1 waits = 5 chngs = '0' endln = '0' while True: (WD_LST ,HT_LST)= (self.dlg_prs.get('w_list', 300) ,self.dlg_prs.get('h_list', 500)) (WD_ACTS ,HT_ACTS)=(self.dlg_prs.get('w_acts', 300) ,self.dlg_prs.get('h_acts', 500)) (WD_BTN ,HT_BTN)= (self.dlg_prs.get('w_btn', 150), 24) l_btn = GAP+WD_LST+GAP vw_acts = (WD_ACTS>0) WD_ACTS = max(0, WD_ACTS) rec_on = ed.get_prop(app.PROP_MACRO_REC) lmcrs = len(self.macros) pass; LOG and log('mcr_ind,vw_acts,rec_on={}',(mcr_ind,vw_acts,rec_on)) nmkys = [] for mcr in self.macros: mcr_cid = 'cuda_macros,run,{}'.format(mcr['id']) mcr_keys= keys.get(mcr_cid, {}) kys = '/'.join([' * '.join(mcr_keys.get('s1', [])) ,' * '.join(mcr_keys.get('s2', [])) ]).strip('/') nmkys += [mcr['nm'] + (' ['+kys+']' if kys else '')] mcr_acts= '' if vw_acts and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] mcr_acts= '\t'.join(['# '+nmkys[mcr_ind]] + mcr['evl']) ans = app.dlg_custom('Macros' ,GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS+GAP,GAP+HT_LST+GAP, '\n'.join([] +[C1.join(['type=listbox' ,POS_FMT(l=GAP, t=GAP, r=GAP+WD_LST, b=GAP+HT_LST) ,'items=' +'\t'.join(nmkys) ,'val=' +str(mcr_ind) # start sel ,'en=' +str(0 if rec_on else 1) # enabled ] # i=0 )] +([C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*1+HT_BTN*0, r=l_btn+WD_BTN, b=0) ,'cap=&View actions...' ,'props=' +str(0 if rec_on or 0==lmcrs else 1) # default ,'en=' +str(0 if rec_on or 0==lmcrs else 1) # enabled ] # i=1 )] if vw_acts else []) +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*2+HT_BTN*1, r=l_btn+WD_BTN, b=0) ,'cap=Hot&keys...' ,'en=' +str(0 if rec_on or 0==lmcrs else 1) # enabled ] # i=2 if vw_acts else i=1 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*3+HT_BTN*2, r=l_btn+WD_BTN, b=0) ,'cap=Re&name...' ,'en=' +str(0 if rec_on or 0==lmcrs else 1) # enabled ] # i=3 if vw_acts else i=2 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*4+HT_BTN*3, r=l_btn+WD_BTN, b=0) ,'cap=&Delete...' ,'en=' +str(0 if rec_on or 0==lmcrs else 1) # enabled ] # i=4 if vw_acts else i=3 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*6+HT_BTN*5, r=l_btn+WD_BTN, b=0) ,'cap=&Run!' ,'props=' +str(1 if not vw_acts and not rec_on else 0) # default ,'en=' +str(0 if rec_on or 0==lmcrs else 1) # enabled ] # i=5 if vw_acts else i=4 )] +[C1.join(['type=label' ,POS_FMT(l=l_btn, t=GAP*7+HT_BTN*6+3, r=l_btn+int(WD_BTN/3),b=0) ,'cap=&Times' ] # i=6 if vw_acts else i=5 )] +[C1.join(['type=spinedit' ,POS_FMT(l=l_btn+int(WD_BTN/3)+GAP, t=GAP*7+HT_BTN*6, r=l_btn+WD_BTN, b=0) ,'val=' +str(times) ,'props=0,{},1'.format(self.dlg_prs.get('times', 1000)) ,'en=' +str(0 if rec_on else 1) # enabled ] # i=7 if vw_acts else i=6 )] +[C1.join(['type=label' ,POS_FMT(l=l_btn, t=GAP*8+HT_BTN*7+3, r=l_btn+int(WD_BTN/3),b=0) ,'cap=&Wait' ] # i=8 if vw_acts else i=7 )] +[C1.join(['type=spinedit' ,POS_FMT(l=l_btn+int(WD_BTN/3)+GAP, t=GAP*8+HT_BTN*7, r=l_btn+WD_BTN-40, b=0) ,'val=' +str(waits) ,'props=1,3600,1' ,'en=' +str(0 if rec_on else 1) # enabled ] # i=9 if vw_acts else i=8 )] +[C1.join(['type=label' ,POS_FMT(l=l_btn+WD_BTN-40+GAP, t=GAP*8+HT_BTN*7+3, r=l_btn+WD_BTN,b=0) ,'cap=sec' ] # i=10 if vw_acts else i=9 )] +[C1.join(['type=check' ,POS_FMT(l=l_btn, t=GAP*9+HT_BTN*8, r=l_btn+WD_BTN,b=0) ,'cap=While text c&hanges' ,'val=' +chngs ] # i=11 if vw_acts else i=10 )] +[C1.join(['type=check' ,POS_FMT(l=l_btn, t=GAP*10+HT_BTN*9, r=l_btn+WD_BTN,b=0) ,'cap=Until c&aret on last line' ,'val=' +endln ] # i=12 if vw_acts else i=11 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*12+HT_BTN*11, r=l_btn+WD_BTN, b=0) ,'cap={}'.format('&Stop record' if rec_on else '&Start record') ,'props=' +str(1 if rec_on or 0==lmcrs else 0) # default ] # i=13 if vw_acts else i=12 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP*13+HT_BTN*12, r=l_btn+WD_BTN, b=0) ,'cap=Canc&el record' ,'en=' +str(1 if rec_on else 0) # enabled ] # i=14 if vw_acts else i=13 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t= HT_LST-HT_BTN*2, r=l_btn+WD_BTN, b=0) ,'cap=C&ustom...' ,'en=' +str(0 if rec_on else 1) # enabled ] # i=15 if vw_acts else i=14 )] +[C1.join(['type=button' ,POS_FMT(l=l_btn, t=GAP+HT_LST-HT_BTN*1, r=l_btn+WD_BTN, b=0) ,'cap=&Close' ] # i=16 if vw_acts else i=15 )] +([C1.join(['type=memo' ,POS_FMT(l=GAP+WD_LST+GAP+WD_BTN+GAP, t=GAP, r=GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS, b=GAP+HT_ACTS) ,'val='+mcr_acts ,'props=1,1,1' # ro,mono,border ] # i=17 )] if vw_acts else []) ), apx.icase( vw_acts and not rec_on, 0 # View ,not vw_acts and not rec_on, 0 # View , vw_acts and rec_on, 11 ,not vw_acts and rec_on, 10 )) # start focus pass; LOG and log('ans={}',ans) if ans is None: break #while (ans_i ,vals) = ans ans_s = apx.icase(False,'' ,vw_acts and ans_i==1, 'view' ,vw_acts and ans_i==2, 'hotkeys' ,not vw_acts and ans_i==1, 'hotkeys' ,vw_acts and ans_i==3, 'rename' ,not vw_acts and ans_i==2, 'rename' ,vw_acts and ans_i==4, 'delete' ,not vw_acts and ans_i==3, 'delete' ,vw_acts and ans_i==5, 'run' ,not vw_acts and ans_i==4, 'run' ,vw_acts and ans_i==12,'rec' ,not vw_acts and ans_i==7, 'rec' ,vw_acts and ans_i==14,'cancel' ,not vw_acts and ans_i==13,'cancel' ,vw_acts and ans_i==15,'custom' ,not vw_acts and ans_i==14,'custom' ,vw_acts and ans_i==16,'close' ,not vw_acts and ans_i==15,'close' ,'?') mcr_ind = int(vals.splitlines()[0]) times = int(vals.splitlines()[ 7 if vw_acts else 6]) waits = int(vals.splitlines()[ 9 if vw_acts else 8]) chngs = vals.splitlines()[11 if vw_acts else 10] endln = vals.splitlines()[12 if vw_acts else 11] pass; LOG and log('mcr_ind,times,waits,chngs,endln={}',(mcr_ind,times,waits,chngs,endln)) if 0!=lmcrs and mcr_ind in range(lmcrs): mcr = self.macros[mcr_ind] self.last_mcr_id = mcr['id'] if ans_s=='close': break #while if ans_s=='custom': #Custom custs = app.dlg_input_ex(5, 'Custom dialog Macros' , 'Height of macro list (min 450)' , str(self.dlg_prs.get('h_list', 400)) , 'Width of macro list (min 200)' , str(self.dlg_prs.get('w_list', 500)) , 'Width of action list (min 200, <=0-hide)', str(self.dlg_prs.get('w_acts', 500)) , 'Width of buttons (min 150)' , str(self.dlg_prs.get('w_btn', 150)) , 'Max run times (min 100)' , str(self.dlg_prs.get('times', 1000)) ) if custs is not None: self.dlg_prs['h_list'] = max(450, int(custs[0])); self.dlg_prs['h_acts'] = self.dlg_prs['h_list'] self.dlg_prs['w_list'] = max(200, int(custs[1])) self.dlg_prs['w_acts'] = max(200, int(custs[2])) if int(custs[2])>0 else int(custs[2]) self.dlg_prs['w_btn'] = max(150, int(custs[3])) self.dlg_prs['times'] = max(100, int(custs[4])) open(MACROS_JSON, 'w').write(json.dumps({'ver':JSON_FORMAT_VER, 'list':self.macros, 'dlg_prs':self.dlg_prs}, indent=4)) continue #while if mcr_ind not in range(lmcrs): app.msg_box('Select macro', app.MB_OK) continue #while what = '' changed = False if False:pass elif ans_s=='view': #View continue #while elif ans_s=='rename': #Rename mcr_nm = app.dlg_input('New name for: {}'.format(nmkys[mcr_ind]) ,mcr['nm']) if mcr_nm is None or mcr_nm==mcr['nm']: continue #while while mcr_nm in [mcr['nm'] for mcr in self.macros]: app.msg_box('Select other name.\nMacro names now are:\n\n'+'\n'.join(nmkys), app.MB_OK) mcr_nm = app.dlg_input('New name for: {}'.format(nmkys[mcr_ind]) ,mcr_nm) if mcr_nm is None or mcr_nm==mcr['nm']: break #while mcr_nm if mcr_nm is None or mcr_nm==mcr['nm']: continue #while what = 'rename' mcr['nm'] = mcr_nm changed = True elif ans_s=='delete': #Del if app.msg_box( 'Delete macro\n {}'.format(nmkys[mcr_ind]) , app.MB_YESNO)!=app.ID_YES: continue #while what = 'delete:'+str(mcr['id']) del self.macros[mcr_ind] mcr_ind = min(mcr_ind, len(self.macros)-1) changed = True elif ans_s=='hotkeys': #Hotkeys app.dlg_hotkeys('cuda_macros,run,'+str(mcr['id'])) keys = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {} changed = True elif ans_s=='run': #Run if (times==0 and waits==0 and chngs=='0' and endln=='0'): app.msg_box('Select stop condition', app.MB_OK) continue self.run(mcr['id'], max(0, times), max(0, waits), chngs=='1', endln=='1') return elif ans_s=='rec' and not rec_on: #Start record return ed.cmd(cmds.cmd_MacroStart) elif ans_s=='rec' and rec_on: #Stop record self.need_dlg = True return ed.cmd(cmds.cmd_MacroStop) # Return for clear rec-mode in StatusBar, will recall from on_macro elif ans_s=='cancel' and rec_on: #Cancel record return ed.cmd(cmds.cmd_MacroCancel) # Return for clear rec-mode in StatusBar if changed: self._do_acts(what)