Given a path to a primary file and a menu path, a section name and a command key, extract a command from a QEditor menu and execute it. Useful from context menu entries. Example use DoM.py -m {o}\menus.ini do.py * list, on my computer searches c:\source\python\menus.ini for the first command whose key begins with list. The command is executed without capturing its standard output.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | mHelpText = '''
# ----------------------------------------------
# Name: DoM
# Description: Expand and execute command from menu
## D20H-53 Expand and execute command
#
# Author: Philip S. Rist
# Date: 10/26/2010
# Copyright 2010 by St. Thomas Software
# ----------------------------------------------
# This program is freeware. It may be used
# for any moral purpose. You use it at your
# own risk. St. Thomas Software makes no
# guarantees to its fitness to do anything.
#
# If you feel you must pay for it. Please
# send one million dollars to
#
# The International Rescue Committee
# 122 East 42nd Street
# New York, N.Y. 10168-1289
#
# Ok, we are in a recession. So, make it a half
# million.
# DoM.py -
# The specified command in the specified section in the specified menu file will
# be expanded with Do.py and executed.
# Usage examples:
#
#[HKEY_CLASSES_ROOT\*\Shell\Rundom]
#@="Run"
#"EditFlags"=hex:01,00,00,00
#[HKEY_CLASSES_ROOT\*\Shell\Rundom\Command]
#@="c:\\sys\\python25\\pythonw.exe c:\\bin\\dom.py -m c:\bin\menus.ini \"%1\" project open "
#
# Syntax:
# dom.py [ options ] <file path> <section> <command key>
#
# Options:
# -d <path> - set current working directory
# -e <name>=<value> - set environment variable
# -h - display this text, everything else is ignored
# -l - list available commands, everything else is ignored
# -m <menu path> - set path to menu file
# default: '{o}\menus.ini;{i}\menus.ini' <- can be changed
# -v - run in verbose mode
# Sample menu file
[DOS]
Open,c:\source\TextFiles\qeditor.exe "{a}"
; Open file
Print,c:\windows\nodepad.exe /P "{a}"
; Print file
Edit,c:\windows\system32\wscript.exe c:\bin\editit.vbs "{a}"
; Edit file with Notetab
Save,C:\Windows\system32\wscript.exe c:\bin\Util.vbs /S "{a}"
Has Been Ssved,C:\Windows\system32\wscript.exe c:\bin\Util.vbs /K "{a}"
UnTabify,c:\sys\python25\python.exe c:\sys\python25\tools\scripts\untabify.py "{a}"
U2M,c:\bin\u2m.bat "{a}"
Echo,c:\bin\messagebox.exe "{a}"
Dir,c:\windows\system32\cmd.exe /C dir "{p}\*.{e}"
'''
import sys
import os
import getopt
import Do # Recipe: 577439
import Do2 # Recipe: 577440
import subprocess
def FindCommand(pKey, pFilePath, pSearchPath, pSection, pList=False, pVerbose=False):
'''
Find command keyword and extract containing line
pKey -- String identifying line to use as command template
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command
pSection -- Section containing command
pList --
'''
if pVerbose:
print 'DoM.py FindCommand:', pKey, pFilePath, pSearchPath, pSection
if not os.path.exists(pSearchPath):
lCommand = ''
print 'DoM.py Could not find menu file', pSearchPath
else:
lSection = pSection.lower()
lKey = pKey.lower()
# ---- Load menu file
lFile = open(pSearchPath, 'r')
lText = lFile.readlines()
lFile.close()
if len(lText) < 1:
print 'DoM.py Menu', pSearchPath, 'read failed'
lFound = False
lCommand = ''
lCount = 0
if pList:
print 'DoM.py Available commands in', pSearchPath
# ---- Scan menu file
for lLine in lText:
lLine = lLine.lstrip()
if len(lLine) < 1:
continue
# ---- Start of section
if lLine[0] == '[':
lCount = 0
lPos = lLine.find(']')
if lPos > 0:
lFoundSection = lLine[1:lPos].lower()
else:
lFoundSection = ''
# ---- Check for conditions, conditions are ignored
if lFoundSection[0] == '/':
lPos2 = lFoundSection.rfind('/')
if lPos2 >= 0:
lFoundSection = lFoundSection[lPos2+1:]
elif lFoundSection[0] == '!':
lPos2 = lFoundSection.rfind('!')
if lPos2 >= 0:
lFoundSection = lFoundSection[lPos2+1:]
#if lSection != lFoundSection and lSection != '*':
if not lFoundSection.startswith(lSection) and lSection != '*':
if pVerbose:
print 'DoM.py not found', lSection, 'in', lFoundSection
if lFound == True:
break
continue
elif lSection != '*' and lFound == True:
break
else:
if pVerbose:
print 'DoM.py found', lSection, 'in', lFoundSection
if pList:
print 'DoM.py Section:', lFoundSection
lFound = True
# ---- Comments
elif lLine[0] == ';':
if lFound and pList:
print 'DoM.py ', lLine,
# ---- Command lines and label lines
else:
if not lFound:
continue
if lLine[0] == '-':
continue
lPos = lLine.find(',')
if lPos > 0:
lMatch = lLine[0:lPos].lower()
else:
continue
# ---- Check for conditions, conditions are ignored
if lMatch[0] == '/':
lPos2 = lMatch.rfind('/')
if lPos2 >= 0:
lMatch = lMatch[lPos2+1:]
elif lMatch[0] == '!':
lPos2 = lMatch.rfind('!')
if lPos2 >= 0:
lMatch = lMatch[lPos2+1:]
lCount += 1
if pList:
if lPos > 0:
lLineText = lLine[lPos+1:]
print "DoM.py %5d: %-20s| %s" % (lCount, lMatch, lLineText),
# ---- Check for matching command
#if lKey == lMatch: # must match command key
if lMatch.startswith(lKey): # command key starts with key
lCommand = lLine[lPos+1:]
if pVerbose:
print 'DoM.py found command', lKey, 'in', lMatch, 'for', lCommand
break
else:
print 'DoM.py no command found in', pSearchPath, pSection
return lCommand[0:-1]
def Expand(pArgs, pFilePath, pSearchPath, pSection, pSep='!!', pList=False, pVerbose=False):
'''
Extract command from file and replace all macros
pArgs -- Args passed to program except file path and section name
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command '
pCount -- Number of lines at the start of the file to scan
pSep -- String used to identify end of command
pHelp -- True to display available commands
'''
# ---- Find command
lCommand = FindCommand(pArgs[0], pFilePath, pSearchPath, pSection, pList=pList, pVerbose=pVerbose)
# ---- Expand and insert/append any passed arguments
# Arguments on original pb.py command line will replace {} from left to right
# otherwise they will be appended to the end of the command
lStart = 1
if len(lCommand) > 0:
if len(pArgs) > lStart:
for lArg in pArgs[lStart:]:
if lArg.find('{') >= 0:
lArg = Do2.ExpandArg(lArg, pFilePath, '')
if len(lArg) > 0:
try:
lTest = os.path.abspath(lArg)
if os.path.exists(lTest):
if lTest.find(" ") > 0:
lTest = '"' + lTest + '"'
lArg = lTest
except:
pass
lPos = lCommand.find('{}')
if lPos >= 0:
lCommand = lCommand[0:lPos] + lArg + lCommand[lPos+2:]
else:
lCommand += ' ' + lArg
# ---- Prevent unwanted arguments appended to command
lPos = lCommand.rfind(pSep)
if lPos > 0:
lCommand = lCommand[0:lPos]
# ---- Expand all remaining macros
if lCommand.find('{') >= 0:
lCommand = Do.Expand(lCommand, pFilePath)
return lCommand
def submitnow(pArgs, pFilePath, pSearchPath, pSection, pVerbose, pList=False):
'Expand and submit command'
if pVerbose:
print 'DoM.py File path:', pFilePath
print 'DoM.py Menu path:', pSearchPath
print 'DoM.py Section: ', pSection
print 'DoM.py Arguments:', pArgs
lCommand = Expand(pArgs, pFilePath, pSearchPath, pSection, pList=pList, pVerbose=pVerbose)
# ---- Any macro not expanded will be assumed to be an environment variable
# If %...% had been used it would have been replaced when pb.py was run
lCommand = lCommand.replace('{}',' ') #<-- may want to do something else
lCommand = lCommand.replace('{', '%') # try to replace with environment variable
lCommand = lCommand.replace('}', '%')
if len(lCommand) == 0:
print 'DoM.py Expansion failed'
else:
lCommand = '"' + lCommand + '"'
if pVerbose:
print 'DoM.py Submitting: ', lCommand
subprocess.Popen(lCommand, shell=True)
def setenviron(pValue, pFileName):
'Set environment variable'
lParts = pValue.split('=')
if len(lParts) > 1:
lKey = lParts[0]
lValue = lParts[1]
if lValue.find('{') >= 0:
lValue = Do2.ExpandArg(lValue, pFileName, '')
os.environ[lKey] = lValue
else:
os.environ[pValue] = ''
if __name__ == '__main__':
(mOptions, mArgs) = getopt.getopt(sys.argv[1:], 'd:e:hlm:v')
mVerbose = False
mHelp = False
mList = False
mSearchPath = '{o}\menus.ini;{i}\menus.ini'
for (mKey, mValue) in mOptions:
if mKey == '-d': # Set current directory
if mValue.find('{') >= 0:
if len(mArgs) > 2:
mFilePath = os.path.abspath(mArgs[0])
mValue = Do.ExpandArg(mValue, mFilePath)
else:
print 'DoM.py No primary file, could not set directory'
break
else:
os.chdir(mValue)
elif mKey == '-e': # Set environment variable
setenviron(mValue, mFilePath)
elif mKey == '-h':
print mHelpText
mHelp = True
elif mKey == '-l':
mList = True
elif mKey == '-m': #
mSearchPath = mValue
elif mKey == '-v':
mVerbose = True
if len(mArgs) > 2:
mFilePath = os.path.abspath(mArgs[0])
mSection = mArgs[1]
if mSection.find('{'):
mSection = Do.Expand(mSection, mFilePath)
mKey = mArgs[2]
if mKey.find('{'):
mArgs[2] = Do.Expand(mKey, mFilePath)
mArgs[2] = mArgs[2].replace('_', ' ')
if mSearchPath.find('{') >= 0:
mSearchPath = Do2.ExpandArg(mSearchPath, mFilePath, '')
if mSearchPath[0] == '"':
mSearchPath = mSearchPath[1:-1]
mSearchPath = os.path.abspath(mSearchPath)
if mHelp:
print 'DoM.py Default menu: ', mSearchPath
print 'DoM.py Default section:', mSection
elif mList:
Expand('???', mFilePath, mSearchPath, mSection, mVerbose, mList)
else:
submitnow(mArgs[2:], mFilePath, mSearchPath, mSection, mVerbose)
elif mHelp == False:
print 'DoM.pyCommand and/or file path missing'
|
Complicated commands can be saved in a QEditor style menu file. This is especially convenient when QEditor or one of my button bar programs is also being used. These use the same menu files. Executing a command from a file type association can reduce redundancy and increase flexibiity. Normal associations can insert only the file name of the clicked file. DoM can generate names for multiple files and search folder trees for suilable files using Do2.py.
'DoM.py -m {p}\menus.ini;{o}\menus.ini StoryWriter.py Fantasy Emarald' will check for menus.ini first in the folder containing StoryWriter then in the base Python menu c:\source\python for a menus.ini file. It will use the first it finds. It will scan the file for a section whos name starts with 'Fantasy' and a command with a name starting with 'Emarald'. When found the command is expanded and executed.
Does not recognize {open} style macros which access the Win32 registry as do my button bar programs. It also ignores the special commands ;#set, ;#cd, ;#button and ;#label used by the button bar programs. Otherwise menu files should be useable by either program.