Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /usr/bin/env python3
- import os, os.path, re, stat, termios, fcntl, sys, string, operator, struct, gc, time
- from optparse import OptionParser
- from unicodedata import east_asian_width
- from subprocess import *
- def usage_help_text():
- print("""Usage
- kingbash relies on the environment variables READLINE_LINE and READLINE_POINT which are automatically set by bind -x.
- When READLINE_POINT is not set, it is presumed 0.
- One can test functionality of tab completion by setting READLINE_LINE (and optionally READLINE_POINT to the length of READLINE_LINE) with export and calling kingbash without arguments.
- When completing a command instead of a file, extra commands (functions, aliases, builtins) and files (so far only bash variables starting with $) can be supplied with --extracommands and --extrafiles respectively as one large string with items delimited by newlines.
- history completion can be tested by piping data to kingbash, or using the option -r FILE
- No READLINE_X variables need to be set in this case.
- Note that by piping data to kingbash, the program will NOT return a value to be interpreted as a new READLINE_POINT so any bind -x script will have to use -r FILE
- Special options:
- --forceheight N : make the screen N character instead of 1/3 of the terminal
- --slowhistory : prefer the older history style. Recommended with few items.
- --noretab-(az|backspace|directory) : don't complete after X
- --plustoall : allows * in tab completion and + will complete all files. Allows you to type a later part of the filename.
- --historytabcompletion : Remove the TAB binding from TAB/Insert's Copy selected item to the prompt, and make it work like TAB completion.
- --uniquereversesort : sort the file loaded with -r FILE in reverse without duplicate entries
- --bashcompletion : use command arguments from /etc/bash_completion.d/
- --wraplonglines : wrap mode
- --bashcompletionexception : for use with undesirable bash completions commands, space delimited. By default does only mplayer.
- --atime : sort by access time
- --mtime : sort by modification time
- --reverse : reverse the sort
- Tab Completion:
- function kingbash.fn() {
- echo -n "KingBash> $READLINE_LINE" #Where "KingBash> " looks best if it resembles your PS1, at least in length.
- OUTPUT=`"""+os.path.split(sys.argv[0])[-1]+""" --bashcompletion --plustoall --noretab-backspace --extracommands "$(compgen -ab -A function)" --extrafiles "$(compgen -v -P $)"`
- READLINE_POINT=`echo "$OUTPUT" | tail -n 1`
- READLINE_LINE=`echo "$OUTPUT" | head -n -1`
- echo -ne "\\r\\e[2K"; }
- [[ $- =~ i ]] && bind -x '"\\t":kingbash.fn'
- Alternative with neater long line handling:
- PS1+='\[\e[s\]'
- function kingbash.fn() {
- local KBCOUNT OUTPUT KBMOVE KBLINES
- for ((unused=0; unused<20; unused++)); do read -n 1 -t 0.000000001; done #clear input buffer
- echo -ne '\e[u\e[6n'
- read -sdR
- [[ $REPLY =~ ..([0-9]*).([0-9]*) ]]
- (( ${BASH_REMATCH[1]} == LINES )) && KBMOVE=A || KBMOVE=B
- KBLINES=$(((${BASH_REMATCH[2]} + ${#READLINE_LINE} ) / COLUMNS))
- for ((KBCOUNT=0;KBCOUNT < $KBLINES; KBCOUNT++)); do
- echo -ne '\r\e[2K\e['$KBMOVE
- done
- if [[ $KBLINES != 0 && $KBMOVE == B ]]; then
- echo -ne "\e[$KBLINES"A
- fi
- echo -ne "${READLINE_LINE:0:$((COLUMNS-${BASH_REMATCH[2]}))}"
- OUTPUT=$("""+os.path.split(sys.argv[0])[-1]+""" --bashcompletion --plustoall --noretab-backspace --extracommands "$(compgen -ab -A function)" --extrafiles "$(compgen -v -P $)")
- READLINE_POINT=$(echo "$OUTPUT"|tail -n1)
- READLINE_LINE=$(echo "$OUTPUT"|head -n -1)
- echo -ne '\r\e[2K'
- [[ $PS1 =~ \\n ]]
- for (( KBCOUNT=0; KBCOUNT < ${#BASH_REMATCH}; KBCOUNT++ )); do
- echo -ne '\e[A\r\e[2K'
- done
- }
- bind -x '"\t":kingbash.fn'
- History search:
- function kingbash.hs() {
- old_line=$READLINE_LINE
- echo -n "KingBash> $READLINE_LINE"
- history -a
- OUTPUT=`"""+os.path.split(sys.argv[0])[-1]+""" -r <(tac $HISTFILE)`
- #Alternatively, for unique entries:
- # OUTPUT=`"""+os.path.split(sys.argv[0])[-1]+""" -r <(tac $HISTFILE | cat -n - | sort -u -k 2 | sort -n | cut -f2-)`
- READLINE_POINT=`echo "$OUTPUT" | tail -n 1`
- READLINE_LINE=`echo "$OUTPUT" | head -n -1`
- echo -ne "\\r\\e[2K"
- #Press Enter Automatically:
- #[ "$old_line" != "$READLINE_LINE" ] && { sleep 0.1; xdotool key --clearmodifiers Return; }
- }
- [[ $- =~ i ]] && bind -x '"\\x12":kingbash.hs'
- CLI dmenu:
- ... | """+os.path.split(sys.argv[0])[-1]+"""
- GUI dmenu:
- rm /tmp/menu
- cat > /tmp/inmenu
- urxvt -e bash -c 'export READLINE_POINT=0; answ=$(""" + os.path.split(sys.argv[0])[-1] + """ -r /tmp/inmenu | head -n 1); echo -n "$answ" > /tmp/menu'
- while sleep 0.1; do [ -f /tmp/menu ] && break; done
- cat /tmp/menu
- rm /tmp/menu
- rm /tmp/inmenu
- -------
- F1 inside the application will print a key table""")
- def F1_help_text():
- sys.stderr.write("""Get usage advice by running """+sys.argv[0]+""" without arguments
- -------------------------
- There are two modes: Tab completion and History/file/dmenu completion.
- ---Key table---
- +Both modes+
- F1 This help
- Up/Down
- Shift+Up/Down
- Shift+Left/Right
- Alt+Left/Right
- Control+A
- Control+E
- Page up/Pagedown
- Home/End Move around the list
- Enter Complete the selection and quit
- Any other character is added "as is" (with the escape sequence replaced with ESC).
- Under "Tab completion" the program quits after a space or equals sign.
- +Tab Completion+
- F2 Erase first word and move cursor to start of line, after the selection has been completed
- Left Go to the parent directory and continue browsing
- Right Complete the selection, but if it's a directory, bring up the program again inside that directory
- Escape Quit, leaving the line as it is seen in the application
- Backspace Erase the character left of the cursor and complete again
- Alt+Backspace Same, but an entire word or path
- Control+U Clear the line and quit
- Insert Complete the selection, move the selector bar down, and continue as if we are completing the previous selection again
- Asterisk Add everything in the list to the command line. If there are 'suggestions', only complete those. Quit afterwards.
- Tab Quit, don't complete the filename but leave the path.
- +History Completion+
- Left Move the cursor left
- Right Move the cursor right
- Escape Quit, restore the line to what it was when KingBash started
- Backspace Erase the character left of the cursor
- Alt+Backspace Same, but an entire word or path
- *Delete Delete the character under the cursor
- Control+U Clear the line and continue
- Tab Make the current line the same as the selection
- Insert Like Tab
- F2 Accept line as is. Like dmenu Shift+Enter (which is not possible to `read`).
- * means this key does nothing at all in the other mode
- -------------------------
- """)
- def main():
- try:
- fd=sys.stdin.fileno()
- oldterm=termios.tcgetattr(fd)
- dmenu_mode=False
- del fd
- del oldterm
- except termios.error: #stdin is a pipe
- dmenu_mode=True
- try:
- point=int(os.environ["READLINE_POINT"])
- except:
- if not dmenu_mode:
- usage_help_text()
- sys.exit(0)
- else:
- point=0
- try:
- line=os.environ["READLINE_LINE"]
- except KeyError:
- line=""
- try:
- point=len(line.encode("UTF8")[0:point].decode("UTF8"))
- except:
- pass
- original_line=line
- original_point=point
- parser=OptionParser()
- parser.add_option("-r", "--readfile", action="store", type="string", dest="readfile", default=False,
- help="Instead of command or files, select from a custom list with entries in FILE")
- parser.add_option("--extracommands", action="store", type="string", dest="extracommands", default="",
- help="Tab completion extra commands (like aliases, functions and builtins")
- parser.add_option("--extrafiles", action="store", type="string", dest="extrafiles", default="",
- help="Tab completion extra files (like variables with compgen -v -P $")
- parser.add_option("--rerun", action="store_true", dest="rerun", default=False,
- help="Let Kingbash know it is on a second run")
- parser.add_option("--selected", action="store", type="int", dest="selected", default=0,
- help="Begin with highlighting this entry")
- parser.add_option("--viewmin", action="store", type="int", dest="viewmin", default=0,
- help="Begin with this entry at page start")
- parser.add_option("--slowhistory", action="store_true", dest="slowhistory", default=False,
- help="Prefer to calculate the history all at once instead of after scrolling")
- parser.add_option("--forceheight", action="store", type="string", dest="forceheight", default="0",
- help="Force height of N (try $LINES) instead of a third of the screen")
- parser.add_option("--loadpages", action="store", type="int", dest="loadpages", default=10,
- help="Amount of pages to load per update in dmenu/history mode for comfortable page down")
- parser.add_option("--noretab-az", action="store_true", dest="noretab_az", default=False,
- help="After pressing a key, behave like regular tab completion and don't try to complete again")
- parser.add_option("--noretab-backspace", action="store_true", dest="noretab_backspace", default=False,
- help="After pressing backspace, behave like regular tab completion and don't try to complete again")
- parser.add_option("--noretab-directory", action="store_true", dest="noretab_directory", default=False,
- help="After pressing Left/Right, behave like regular tab completion and don't try to complete again")
- parser.add_option("--plustoall", action="store_true", dest="plustoall", default=False,
- help="Allows * in tab completion. Will be interpreted as either \* when quitting, or glob when continuing to type, which allows you to search the completions more easily.")
- parser.add_option("--historytabcompletion", action="store_true", dest="historytabcompletion", default=False,
- help="Allows TAB completion in history/dmenu mode. Insert will still copy the current selected item to the prompt as TAB did before.")
- parser.add_option("--uniquereversesort", action="store_true", dest="uniquereversesort", default=False,
- help="Sort -r FILE first in reverse and then removing duplicates.")
- parser.add_option("--bashcompletion", action="store_true", dest="bashcompletion", default=False,
- help="Run the line through /etc/bash_completions.d.")
- parser.add_option("--bashcompletionexception", action="store", type="string", dest="bashcompletionexception", default="mplayer",
- help="Space delimited list of names of commands not to look up completions for.")
- parser.add_option("--wraplonglines", action="store_true", dest="wraplonglines", default=False,
- help="Don't cut lines, but wrap them and still show them neatly")
- parser.add_option("--prompt", action="store", type="string", dest="prompt", default="KingBash",
- help="Show a prompt.")
- parser.add_option("--atime", action="store_true", dest="atime", default=False,
- help="sort by access time")
- parser.add_option("--mtime", action="store_true", dest="mtime", default=False,
- help="sort by modification time")
- parser.add_option("--reverse", action="store_true", dest="reverse", default=False,
- help="reverse all sorting")
- global options
- (options,args)=parser.parse_args()
- del args
- options.bashcompletionexception=options.bashcompletionexception.split()
- try:
- screen=int(terminal_size()[0]/3)
- width=terminal_size()[1]
- if screen == 0: screen=0/0
- except:
- screen=23
- width=80
- try:
- forceheight=int(options.forceheight)
- except:
- if options.forceheight=="MAX":
- try:
- forceheight=terminal_size()[0]
- except: pass
- if forceheight != 0: screen=forceheight -3
- original_screen=screen
- if dmenu_mode or options.readfile:
- if dmenu_mode:
- f=os.fdopen(sys.stdin.fileno(), errors="ignore")
- else:
- f=open(options.readfile, errors="ignore")
- file_mode=True
- gc.disable()
- read_file=[]
- for read_f in f:
- read_file.append(read_f[:-1])
- if options.uniquereversesort: #still slower than bash's tac + cat + sort *2 + cut
- seen={}
- new_read_file=[]
- for read_f in reversed(read_file):
- if read_f in seen: continue
- seen[read_f]=1
- new_read_file.append(read_f)
- read_file=new_read_file
- f.close()
- gc.enable()
- (left_off,check_left_off,suggestions)=grep_list(line.split(), read_file, original_screen, [], 0, [], [])
- # filedict=[]
- # for suggestion in suggestions:
- # filedict.append( { "isdir":False, "name":suggestion, "format":"\x1b[m"+suggestion, "rec":False })
- filedict=suggestions
- prework=""
- workpath=""
- is_command=True
- upto=""
- workstr=""
- postwork=""
- cursor=point
- else:
- file_mode=False
- upto=line[:point]
- first_space=re.search("[^\\\\] ", upto)
- if first_space:
- first_space=first_space.start()
- else:
- first_space=point
- workstr=re.match("(.*(?<!\\\\)[ &;|=])(.*)", upto)
- if not workstr:
- prework=""
- workstr=upto
- else:
- prework=workstr.group(1)
- workstr=workstr.group(2)
- #This separates further on $dollar and puts it INSIDE workstr
- dollars=re.match("(.*(?<!\\\\))(\$.*)", workstr)
- if dollars:
- prework+=dollars.group(1)
- workstr=dollars.group(2)
- postwork=line[point:]
- workpath=re.match("(.*/)(.*)",workstr)
- if not workpath:
- workpath=""
- else:
- workstr=workpath.group(2)
- workpath=workpath.group(1)
- if len(workstr) != 0 and workstr[0] == "'":
- workstr=unfixshell_singlequote(workstr)
- else:
- workstr=unfixshell(workstr)
- filedict=[]
- is_command=False
- if len(workpath) == 0:
- if len(prework) == 0: is_command=True
- else:
- if point <= first_space: is_command=True
- if prework[-5:] in ("sudo ", "type "): is_command=True
- if prework[-6:] in ("which "): is_command=True
- if prework[-7:] in ("whatis "): is_command=True
- if prework[-7:] in ("setsid "): is_command=True
- if prework[-8:] in ("whereis "): is_command=True
- if prework[-2:] in ("{ "): is_command=True
- if prework[-1] in ("|", ";", "&", "(") : is_command=True
- if prework[-2:] in ("| ","; ","& ", "( "): is_command=True
- #However
- if prework[-1] == "=" : is_command=False
- if prework[-2:] == "= ": is_comamnd=False
- if workpath != "" and not os.path.isdir(workpath):
- workpath=re.sub("(^|(?<=/))(?P<a>[^~*\/])((?=/)|$)", "\g<a>*", workpath) #Presume single character paths like /u/b are a shortcut for /u*/b
- if is_command:
- suggestions=complete_command(workstr)
- else:
- if workpath == "" and re.search("\\bcd ", prework)!=None:
- try:
- cdpath=os.environ["CDPATH"].split(":")
- suggestions=[]
- for path in cdpath:
- try:
- if path[-1] != "/":
- path+="/"
- except: #empty entry == .?
- pass
- suggestions.extend(map(lambda x: path+x,complete_filename(workstr, unfixshell(path))))
- except:
- suggestions=complete_filename(workstr, unfixshell(workpath))
- elif re.search("(^|(?<!\\\\))\*", workpath) != None:
- suggestions=[]
- ast_paths=Popen("bash -c 'shopt -s nocaseglob; ls -d -1 "+workpath+"/'", shell=True, stdout=PIPE).communicate()[0].decode("utf8").split("\n") #Cheating
- # sys.stderr.write(repr(ast_paths))
- # sys.stderr.flush()
- # os.system("read -p ENTER")
- for path in ast_paths:
- if path == "": continue
- try:
- if path[-1] != "/":
- path+="/"
- except: pass
- suggestions.extend(map(lambda x: path+x, complete_filename(workstr, unfixshell(path))))
- workpath=""
- else:
- suggestions=complete_filename(workstr, unfixshell(workpath))
- suggestions=sorted(set(suggestions),key=str.lower)
- if options.bashcompletion and os.path.isfile("/etc/bash_completion"):
- lastcommand_rx=re.sub("(.*(?<!\\\\)[&;|])(.*)", "", upto)
- lastcommand=lastcommand_rx.split()
- if len(lastcommand_rx) > 0 and lastcommand_rx[-1]==" ": lastcommand.append("")
- if len(lastcommand) > 0 and lastcommand[0] not in options.bashcompletionexception and os.path.isfile("/etc/bash_completion.d/"+lastcommand[0]):
- lc_l=""
- for lc_n,lc_c in enumerate(lastcommand):
- lc_l+='; COMP_WORDS['+str(lc_n)+']="'+lc_c+'"'
- cur=""
- prev=""
- if len(lastcommand) > 0: cur=lastcommand[-1]
- if len(lastcommand) > 1: prev=lastcommand[-2]
- # bc_sug=Popen("bash -c 'function have() { :; }; source <(cat /etc/bash_completion.d/"+lastcommand[0]+")"+lc_l+"; COMP_CWORD=$(( ${#COMP_WORDS[@]} -1)); _"+lastcommand[0]+"; echo ${COMPREPLY[@]}'", shell=True, stdout=PIPE).communicate()[0].split()
- # bc_sug_utf=[]
- # bc_sug=Popen("bash -c 'source /etc/bash_completion; function have() { :; }; source /etc/bash_completion.d/"+lastcommand[0]+lc_l+"; COMP_WORDBREAKS=' '; COMP_CWORD=$(( ${#COMP_WORDS[@]} -1)); COMP_LINE=lastcommand_rx; COMP_POINT="+str(len(lastcommand_rx))+"; _"+lastcommand[0]+"""; for opt in "${COMPREPLY[@]}"; do echo "$opt"; done '""", shell=True, stdout=PIPE).communicate()[0].decode("utf8").split("\n")
- bc_sug=Popen("""bash -c '
- source /etc/bash_completion
- function have() { :; }
- source /etc/bash_completion.d/"""+lastcommand[0]+lc_l+"""
- COMP_CWORD=$(( ${#COMP_WORDS[@]} -1))
- function _get_comp_words_by_ref() { cur="""+fixshell(cur)+"""; prev="""+fixshell(prev)+"""; }
- _"""+lastcommand[0]+"""
- for opt in "${COMPREPLY[@]}"; do echo "$opt"; done '""", shell=True, stdout=PIPE).communicate()[0].decode("utf8").split("\n")
- for bc_nr in reversed(range(len(bc_sug))):
- bc_sug[bc_nr]=bc_sug[bc_nr].strip()
- if bc_sug[bc_nr] == "": del bc_sug[bc_nr]
- bc_sug.extend(suggestions)
- suggestions=bc_sug
- if len(suggestions) == 1 and not (len(workstr) == 0 and options.rerun):
- fix=fixshell(suggestions[0])
- if not os.path.isdir(os.path.expandvars(os.path.expanduser(unfixshell(workpath))) + suggestions[0]):
- fix+=" "
- else:
- fix+="/"
- if options.rerun:
- rerun_fn(prework+workpath+fix+postwork, str(len(prework+workpath+fix)))
- print(prework + workpath + fix + postwork)
- print(len((prework + workpath + fix).encode("utf8")))
- return
- if len(suggestions) == 0:
- if len(workstr) != 0:
- if options.rerun:
- print(line)
- print(original_point)
- return
- else:
- lastword=re.match("(.* )(.*)", line)
- if not lastword:
- print(line)
- print(original_point)
- return
- else:
- firstwords=lastword.group(1)
- lastword=lastword.group(2)
- totalrestart=firstwords+lastword
- total_re=re.match("(.*[/ ])(.*)", totalrestart)
- if not total_re:
- total_final=firstwords+lastword
- else:
- total_final=total_re.group(1)+"*"+total_re.group(2)
- # os.environ["READLINE_LINE"]=firstwords+"*"+lastword
- os.environ["READLINE_LINE"]=total_final
- os.environ["READLINE_POINT"]=str(original_point+1)
- # curops=[sys.argv[0], "--rerun", "--selected", str(insert_cursor_move[0]), "--viewmin", str(insert_cursor_move[1])]
- curops=[sys.argv[0], "--rerun"]
- if options.extracommands != "": curops.extend(["--extracommands",options.extracommands])
- if options.extrafiles != "": curops.extend(["--extrafiles",options.extrafiles])
- if options.forceheight != 0: curops.extend(["--forceheight", options.forceheight])
- if options.noretab_az: curops.append("--noretab-az")
- if options.noretab_backspace: curops.append("--noretab-backspace")
- if options.noretab_directory: curops.append("--noretab-directory")
- if options.plustoall: curops.append("--plustoall")
- if options.bashcompletion: curops.append("--bashcompletion")
- if options.reverse: curops.append("--reverse")
- if options.atime: curops.append("--atime")
- if options.mtime: curops.append("--mtime")
- curops.append("--prompt")
- curops.append(options.prompt)
- curops.append("--bashcompletionexception")
- curops.append(" ".join(options.bashcompletionexception))
- if options.wraplonglines: curops.append("--wraplonglines")
- os.execv(sys.argv[0], curops)
- return
- else:
- suggestions=[""]
- if len(workstr) > 0 and workstr[-1] == '\\': workstr=workstr[:-1] #Don't escape the escape for a future character
- first=suggestions[0]
- lcd=[] #find largest common divider
- for last in suggestions[1:]:
- ld=""
- for i in range(min(len(first),len(last))):
- if first[i].upper()==last[i].upper():
- ld=ld+first[i]
- else:
- break
- lcd.append(ld)
- if len(lcd) > 0:
- smallest=sorted(lcd)[0]
- else:
- smallest=""
- if len(smallest) > len(workstr):
- workstr=smallest
- line=prework+workpath+fixshell(workstr)+postwork
- point=len(prework+workpath+fixshell(workstr))
- cursor=len(workpath+workstr)
- if is_command:
- for suggestion in suggestions:
- filedict.append({ "isdir":False, "name":suggestion, "format":"\x1b[7m" + suggestion[:cursor] + "\x1b[m" + suggestion[cursor:], "rec":False, "time":0 })
- else:
- for suggestion in suggestions:
- try:
- statf=os.lstat(os.path.expandvars(os.path.expanduser(unfixshell(workpath)))+suggestion)
- except OSError:
- filedict.append({"isdir":False, "name":suggestion, "format":"\x1b[m[SPC]".ljust(12)+suggestion, "rec":True, "time":0})
- continue
- link_ind=""
- if stat.S_ISLNK(statf[stat.ST_MODE]):
- link_ind=" -> "+os.readlink(os.path.expandvars(os.path.expanduser(unfixshell(workpath)))+suggestion)
- try:
- statf=os.stat(os.path.expandvars(os.path.expanduser(unfixshell(workpath)))+suggestion)
- link_ind=" @"+link_ind
- except OSError:
- link_ind=" @BAD"+link_ind
- time_string=""
- time_int=0
- if options.atime or options.mtime:
- if options.atime:
- time_int=statf[stat.ST_ATIME]
- if options.mtime:
- time_int=statf[stat.ST_MTIME]
- time_string=time.localtime(time_int)
- time_string="["+str(time_string[0])+"-"+str(time_string[1]).rjust(2,"0")+"-"+str(time_string[2]).rjust(2,"0")+" "+str(time_string[3]).rjust(2,"0")+":"+str(time_string[4]).rjust(2,"0")+"] "
- size=statf[stat.ST_SIZE]
- exp=0
- while size >= 1024: size=int(size/1024); exp=exp+1
- size=str(size)+["B","KB","MB","GB","TB"][exp]
- if stat.S_ISDIR(statf[stat.ST_MODE]):
- dirappend="/"
- else:
- dirappend=""
- try:
- if isrecommended(re.sub(".*[^\\\\][;&|]", "", prework).split()[0], suggestion, dirappend=="/"):
- rec=True
- color="\x1b[m\x1b[31m"
- matchcolor="\x1b[31;47m"
- else:
- rec=False
- color="\x1b[m"
- matchcolor="\x1b[30;47m"
- except IndexError:
- rec=False
- color="\x1b[m"
- matchcolor="\x1b[30;47m"
- filedict.append({ "isdir":dirappend=="/", "name":suggestion, "format":time_string+"\x1b[m"+("\x1b[35m(" + size + ")\x1b[m").ljust(17) + matchcolor + str(workpath+suggestion)[:cursor] + color + str(workpath+suggestion)[cursor:] + dirappend + link_ind, "rec":rec, "time":time_int})
- filedict.sort(key=operator.itemgetter("isdir"),reverse=True)
- if options.atime or options.mtime:
- filedict.sort(key=operator.itemgetter("time"))
- if options.reverse:
- filedict.reverse()
- filedict.sort(key=operator.itemgetter("rec"),reverse=True)
- #They default to 0 in optparse
- selected=options.selected
- viewmin=options.viewmin
- count=len(filedict)-1
- if count < screen: screen=count
- #Turn off echo mode (print what you type)
- try:
- fd=sys.stdin.fileno()
- oldterm=termios.tcgetattr(fd)
- except termios.error:
- newin=os.open("/dev/tty", os.O_RDONLY)
- os.dup2(newin, fd)
- oldterm=termios.tcgetattr(fd)
- newattr=termios.tcgetattr(fd)
- newattr[3]=newattr[3] & ~termios.ICANON & ~termios.ECHO
- termios.tcsetattr(fd, termios.TCSANOW, newattr)
- #This makes the cursor invisible, and clears the possible calling-function's replacement prompt
- sys.stderr.write("\x1b[?25l\r\x1b[2K")
- file_mode_changes=False
- change_was_scroll=False
- show_F1_help_text=False
- new_list_is_subset=False
- calculate_all=False
- rerun=False
- insert_cursor_move=False
- already_erased=False
- not_done_recheck=[]
- recheck=[]
- viewmax=False
- oldselected=0
- try:
- while 1:
- if show_F1_help_text:
- F1_help_text()
- show_F1_help_text=False
- if file_mode and file_mode_changes:
- recheck=[]
- if new_list_is_subset:
- original_read_file=read_file
- recheck=suggestions
- suggestions=[]
- viewmin=0
- selected=0
- # check_left_off=0
- new_list_is_subset=False
- elif not change_was_scroll:
- suggestions=[]
- check_left_off=0
- left_off=0
- # check_left_off=0
- recheck=[]
- not_done_recheck=[]
- viewmin=0
- selected=0
- change_was_scroll=False
- if calculate_all:
- backup_original_screen=original_screen
- original_screen=len(read_file)
- (left_off,not_done_recheck,suggestions)=grep_list(line.split(), read_file, original_screen, suggestions, left_off, recheck, not_done_recheck)
- if calculate_all:
- selected=len(suggestions)-1
- original_screen=backup_original_screen
- while viewmin+screen < selected: viewmin+=screen+1
- calculate_all=False
- filedict=[]
- # gc.disable()
- # for suggestion in suggestions:
- # filedict.append( { "isdir":False, "name":suggestion, "format":"\x1b[m"+suggestion, "rec":False })
- # gc.enable()
- filedict=suggestions
- oldcount=count
- count=len(filedict)-1
- if count < 0: count = 0
- if count < original_screen:
- screen=count
- if screen != original_screen and count > original_screen:
- screen=original_screen
- # if not change_was_scroll and oldcount != count: selected=0
- change_was_scroll=False
- file_mode_changes=False
- try:
- unused = line[point+1:]
- sys.stderr.write(options.prompt+"> " + line[:point] + '\x1b[7m' + line[point] + '\x1b[m' + line[point+1:] + '\n')
- except IndexError:
- sys.stderr.write(options.prompt+"> " + line + '\x1b[7m \x1b[m\n')
- oldline=line
- (wrapline_blockscroll, wrapline_blockscroll_bottom, wrapline_todelete)=show_filelist(filedict, selected, viewmin, viewmax, screen, width, original_screen, int(col_count(options.prompt+"> "+oldline)/width))
- # sys.stderr.write( repr( (wrapline_blockscroll, wrapline_blockscroll_bottom, wrapline_todelete, viewmin, viewmax, selected, screen, original_screen) ) )
- sys.stderr.write("-"*width)
- sys.stderr.flush()
- try:
- c=sys.stdin.read(1)
- if c == "\x1b":
- c="ESC"
- oldflags=fcntl.fcntl(fd, fcntl.F_GETFL)
- fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
- while 1:
- try:
- newc=sys.stdin.read(1)
- if newc == "": break # Python 3 doesn't seem to use IOError
- if newc == "\x1b": newc="ESC"
- c=c+newc
- if newc in ("A","B","C","D","a","b","c","d","~"): #Common endings of escape codes of keys that are held down
- break
- except IOError: break
- fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
- if c == "ESC[A":#UP
- selected-=1
- elif c in ("ESC[a","ESC[1;2A"):#SHIFT UP
- selected-=5
- elif c == "ESC[B":#DOWN
- selected+=1
- elif c in ("ESC[b","ESC[1;2B"):#SHIFT DOWN
- selected+=5
- elif c == "ESC[C":#RIGHT
- if file_mode:
- if point != len(line):
- point+=1
- else:
- filedict[selected]["name"]=fixshell(filedict[selected]["name"])
- if not filedict[selected]["isdir"]:
- filedict[selected]["name"]+=" "
- else:
- filedict[selected]["name"]+="/"
- line=prework + workpath + filedict[selected]["name"] + postwork
- point=len(prework + workpath + filedict[selected]["name"])
- if not options.noretab_directory:
- rerun=True
- break
- elif c in ("ESC[D","\x0c"):#LEFT
- if file_mode:
- if point != 0:
- point-=1
- else:
- workstr=""
- oldlen=len(workpath)
- if workpath == "/":
- pass
- elif workpath == "" or workpath[-3:] == "../":
- workpath+="../"
- else:
- oldpath=workpath
- workpath=re.sub("/[^/]*/$", "/", workpath)
- if oldpath == workpath:
- workpath=re.sub(".*?/$", "", workpath)
- del oldpath
- line=prework+workpath+fixshell(workstr)+postwork
- point=point+(len(workpath)-oldlen)
- if not options.noretab_directory:
- rerun=True
- break
- elif c == "ESC[6~":#PAGEDOWN
- selected+=screen+1
- # if viewmin + screen + 1 < count: viewmin+=screen+1
- elif c == "ESC[5~":#PAGEUP
- selected-=screen+1
- # viewmin-=screen+1
- elif c in ("ESC[4~","ESC[F","ESC[8~","ESCOF"):#END
- if selected != count: selected=count+1 #trick to activate below viewmin code
- if file_mode and left_off != len(read_file) or len(recheck)!=0:
- calculate_all=True
- file_mode_changes=True
- elif c in ("ESC[1~","ESC[H","ESC[7~","ESCOH"):#HOME
- selected=0
- viewmin=0
- elif c in ("\x0d", "\n"):#ENTER
- if not file_mode:
- file=fixshell(filedict[selected]["name"])
- if not filedict[selected]["isdir"]:
- file+=" "
- else:
- file+="/"
- else:
- try:
- file=filedict[selected]
- except IndexError:
- file=line
- pass
- line=prework + workpath + file + postwork
- point=len((prework + workpath + file).encode("utf8"))
- break
- elif c == "ESC":#ESCAPE
- if file_mode:
- line=original_line
- point=original_point
- break
- elif c in ("\x7f", "\x08"):#BACKSPACE
- if file_mode:
- if point != 0:
- line=line[:point-1]+line[point:]
- point-=1
- file_mode_changes=True
- else:
- line=prework+str(workpath+workstr)[:-1]+postwork
- point-=1
- if not options.noretab_backspace:
- rerun=True
- break
- elif c in ("ESC\x7f", "ESC\x08"):#ALT+BACKSPACE
- if file_mode:
- try:
- nline=" ".join(line[:point].split(" ")[:-1])+line[point:]
- point-=len(line)-len(nline)
- line=nline
- del nline
- file_mode_changes=True
- except: pass
- else:
- new=re.sub("""[/ '"]?[^/ '"]*?[/ '"]?$""", "", prework+workpath+fixshell(workstr))
- line=new+postwork
- point=len(new)
- if not options.noretab_backspace:
- rerun=True
- break
- elif c in ("ESC[d","ESC[1;2D","ESCESC[D"):#SHIFT LEFT AND ALT LEFT
- newpoint=len(" ".join(line[:point].split(" ")[:-1]))
- if point != newpoint:
- point=newpoint
- if not file_mode:
- break
- elif c in ("ESC[c","ESC[1;2C","ESCESC[C"):#SHIFT RIGHT AND ALT RIGHT
- newpoint=len(line[:point+1]+line[point+1:].split(" ")[0])
- if point != newpoint:
- point=newpoint
- if not file_mode:
- break
- elif c == "\x01":#^A
- if point != 0:
- point=0
- if not file_mode:
- break
- elif c == "\x05":#^E
- if point != len(line):
- point=len(line)
- if not file_mode:
- break
- elif c == "ESC[3~":#DELETE
- if file_mode:
- line=line[:point]+line[point+1:]
- file_mode_changes=True
- elif c == "\x15":#CONTROL + U
- line=""
- point=0
- if not file_mode:
- break
- file_mode_changes=True
- elif c in ("\x09",'\t'):#TAB
- if file_mode:
- if options.historytabcompletion:
- os.environ["READLINE_LINE"]=line
- os.environ["READLINE_POINT"]=str(point)
- # erase_filelist(screen+2 + int( col_count("KingBash> "+line)/width) + wrapline_todelete)
- erase_filelist(1 + int( col_count(options.prompt+"> "+oldline)/width) + wrapline_todelete)
- already_erased=True
- output=Popen([sys.argv[0], "--plustoall", "--noretab-backspace"], stdout=PIPE).communicate()[0].decode("utf8").split("\n")
- newline="\n".join(output[0:-2])
- if newline != line:
- file_mode_changes=True
- line=newline
- point=int(output[-2])
- else:
- try:
- line=filedict[selected]
- point=len(filedict[selected])
- except IndexError:
- pass
- else:
- line=prework + workpath
- point=len(prework + workpath)
- break
- elif c == "ESC[2~":#INSERT
- if not file_mode:
- file=fixshell(filedict[selected]["name"])
- if not filedict[selected]["isdir"]:
- file+=" "
- else:
- file+="/ "
- else:
- try:
- file=filedict[selected]
- except IndexError:
- file=""
- line=prework + workpath + file + workpath + fixshell(workstr) + postwork
- point=len((prework + workpath + file + workpath + fixshell(workstr)).encode("utf8"))
- if not file_mode:
- rerun=True
- selected+=1
- if selected > count: selected=count
- if selected > viewmin + screen: viewmin+=screen+1
- insert_cursor_move=(str(selected), str(viewmin))
- break
- else:
- file_mode_changes=True
- elif ((c == "*" and not options.plustoall) or (c == "+" and options.plustoall)) and not file_mode:#ASTERISK
- line=prework
- point=len(prework.encode("utf8"))
- allfalse=True
- for file in filedict:
- if file["rec"] == False: continue
- allfalse=False
- file["name"]=fixshell(file["name"])+" "
- line+=workpath+file["name"]
- point+=len( (workpath+file["name"]).encode("utf8"))
- if allfalse:
- for file in filedict:
- file["name"]=fixshell(file["name"])+" "
- line+=workpath + file["name"]
- point+=len( (workpath + file["name"]).encode("utf8"))
- line+=postwork
- break
- elif c in ("ESC[13~","ESCOR"):#F3
- if not options.atime and not options.mtime:
- options.atime=True
- options.reverse=True
- options.prompt="ATIME sort"
- elif not options.mtime:
- options.mtime=True
- options.atime=False
- options.reverse=True
- options.prompt="MTIME sort"
- else:
- options.atime=False
- options.mtime=False
- options.reverse=False
- options.prompt="ALPHA sort"
- rerun=True
- break
- elif c in ("ESC[12~","ESCOQ"):#F2
- if not is_command:
- prework=re.sub("^.*?(?<!\\\\) ", "", prework) #remove first word and move cursor there
- prework=" "+prework
- filedict[selected]["name"]=fixshell(filedict[selected]["name"])
- if not filedict[selected]["isdir"]:
- filedict[selected]["name"]+=" "
- else:
- filedict[selected]["name"]+="/"
- line=prework + workpath + filedict[selected]["name"] + postwork
- point=0
- break
- else:
- break
- elif c in ("ESC[11~","ESCOP"):#F1
- show_F1_help_text=True
- else:
- if file_mode:
- if line[:point].split(" ")[-1]+line[point:].split(" ")[0] in line[:point].split(" ")[-1]+ c +line[point:].split(" ")[0]:
- new_list_is_subset=True
- line=line[:point] + c + line[point:]
- point+=len(c)
- file_mode_changes=True
- else:
- point=len(prework + workpath + fixshell(workstr) + c)
- line=prework + workpath + fixshell(workstr) + c + postwork
- if not options.noretab_az and c not in (' ',"="):
- rerun=True
- break
- except IOError: pass
- if selected <= 0:
- selected=0
- viewmax=False
- elif selected >= count:
- selected=count
- while selected > viewmin + screen: viewmin+=screen+1
- viewmax=False
- elif selected > viewmin + screen - wrapline_blockscroll or (viewmax and selected > viewmax):
- viewmin+=screen+1-wrapline_blockscroll
- viewmax=False
- elif selected < viewmin + wrapline_blockscroll_bottom or (viewmax and selected < viewmax-(wrapline_todelete - wrapline_blockscroll_bottom)):
- if selected == oldselected-1:
- viewmax=selected
- else:
- frombottom=oldselected-viewmin
- fromtop=(viewmin+screen+1) - oldselected
- if frombottom < fromtop:
- viewmax=False
- else:
- viewmax=selected+fromtop
- viewmin-=screen+1+wrapline_blockscroll_bottom
- if viewmin < 0: viewmin=0
- if selected < viewmin:
- viewmin=selected
- if file_mode and not options.slowhistory and left_off != len(read_file) and viewmin+screen+2 > len(suggestions):
- file_mode_changes=True
- change_was_scroll=True
- if not already_erased:
- erase_filelist(1 + int(col_count(options.prompt+"> "+oldline)/width) + wrapline_todelete)
- already_erased=False
- oldselected=selected
- except KeyboardInterrupt:
- if file_mode:
- line=original_line
- point=original_point
- finally:
- sys.stderr.write('\x1b[m\x1b[?25h') #default color, make cursor visible
- erase_filelist(1 + int(col_count(options.prompt+"> "+oldline)/width) + wrapline_todelete)
- termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) #restore echo mode
- if rerun:
- rerun_fn(line, point, insert_cursor_move)
- else:
- print(line)
- if not dmenu_mode:
- print(point)
- def rerun_fn(line,point,insert_cursor_move=None):
- os.environ["READLINE_LINE"]=line
- os.environ["READLINE_POINT"]=str(point)
- if not insert_cursor_move:
- del insert_cursor_move
- insert_cursor_move=[0,0]
- curops=[sys.argv[0], "--rerun", "--selected", str(insert_cursor_move[0]), "--viewmin", str(insert_cursor_move[1])]
- if options.extracommands != "": curops.extend(["--extracommands",options.extracommands])
- if options.extrafiles != "": curops.extend(["--extrafiles",options.extrafiles])
- if options.forceheight != 0: curops.extend(["--forceheight", options.forceheight])
- if options.noretab_az: curops.append("--noretab-az")
- if options.noretab_backspace: curops.append("--noretab-backspace")
- if options.noretab_directory: curops.append("--noretab-directory")
- if options.plustoall: curops.append("--plustoall")
- if options.bashcompletion: curops.append("--bashcompletion")
- if options.reverse: curops.append("--reverse")
- if options.atime: curops.append("--atime")
- if options.mtime: curops.append("--mtime")
- curops.append("--prompt")
- curops.append(options.prompt)
- curops.append("--bashcompletionexception")
- curops.append(" ".join(options.bashcompletionexception))
- if options.wraplonglines: curops.append("--wraplonglines")
- os.execv(sys.argv[0], curops)
- # Thanks to http://bytes.com/topic/python/answers/453313-best-way-finding-terminal-width-height
- def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS
- try: ### Discover terminal width
- cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
- except:
- return None
- return cr
- def terminal_size():
- ### decide on *some* terminal size
- # try open fds
- cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
- if not cr:
- # ...then ctty
- try:
- fd = os.open(os.ctermid(), os.O_RDONLY)
- cr = ioctl_GWINSZ(fd)
- os.close(fd)
- except:
- pass
- return int(cr[0]), int(cr[1])
- def complete_command(workstr):
- paths=os.environ["PATH"].split(":")
- paths.append("COMPLETE_ALIASES")
- suggestions=[]
- for path in paths:
- suggestions.extend(complete_filename(workstr, path))
- return suggestions
- def complete_filename(workstr, path):
- if path == "": path="./"
- path=os.path.expandvars(os.path.expanduser(path))
- suggestions=[]
- try:
- if path == "COMPLETE_ALIASES":
- if options.extracommands != "":
- filelist=options.extracommands.split("\n")
- else:
- return []
- else:
- filelist=os.listdir(path)
- if options.extrafiles != "" and len(workstr)>0 and workstr[0]=="$":
- filelist.extend(options.extrafiles.split("\n"))
- if workstr=="..": filelist.append("..")
- for file in filelist:
- try:
- asterisk=re.escape(workstr)
- asterisk=re.sub("\\\\\*",".*",asterisk)
- asterisk=re.sub("\\\\\?",".?",asterisk)
- asterisk+=".*"
- asterisk_match=re.match(asterisk,file,re.I)
- if asterisk_match:
- if len(file) > 0 and file[0] != "$":
- file=re.sub("\\$","\\$",file)
- suggestions.append(file)
- else:
- asterisk_match=re.match(asterisk,fixshell(file),re.I)
- if asterisk_match:
- if len(file) > 0 and file[0] != "$":
- file=re.sub("\\$","\\$",file)
- suggestions.append(file)
- except ValueError: pass
- except OSError: pass
- return suggestions
- def grep_list(patterns, lines, count, good_list, left_off, recheck, not_done_recheck):
- gc.disable()
- count*=options.loadpages #pages loaded at once (for quick page down)
- recheck_left_off=0
- not_done_recheck_left_off=0
- for line in recheck:
- recheck_left_off+=1
- found=True
- for pattern in patterns:
- if pattern.lower() not in line.lower():
- found=False
- break
- if found:# and (len(good_list) == 0 or good_list[-1] != line):
- good_list.append(line)
- if options.slowhistory: continue
- count-=1
- if count < 0:
- break
- recheck=recheck[recheck_left_off:]
- if count >= 0:
- for line in not_done_recheck:
- not_done_recheck_left_off+=1
- found=True
- for pattern in patterns:
- if pattern.lower() not in line.lower():
- found=False
- break
- if found and (len(good_list) == 0 or good_list[-1] != line):
- good_list.append(line)
- if options.slowhistory: continue
- count-=1
- if count < 0:
- break
- recheck=not_done_recheck[not_done_recheck_left_off:]
- if count >= 0:
- for line in lines[left_off:]:
- left_off+=1
- found=True
- for pattern in patterns:
- if pattern.lower() not in line.lower():
- found=False
- break
- if found and (len(good_list) == 0 or good_list[-1] != line):
- good_list.append(line)
- if options.slowhistory: continue
- count-=1
- if count < 0:
- break
- else:
- recheck.extend(not_done_recheck)
- gc.enable()
- return (left_off, recheck, good_list)
- def show_filelist(filedict, selected, viewmin, viewmax, screen, width, original_screen, prompt_extra_lines):
- original_screen-=prompt_extra_lines
- length=len(filedict)-1
- eofs=viewmin+screen
- if eofs > length:
- modeofs=length
- else:
- modeofs=eofs
- try:
- if length % screen != 0:
- modlen=(screen-(length%screen)+length)
- else:
- modlen=length
- except ZeroDivisionError:
- modlen=1
- try:
- dotstart=int(screen*viewmin/modlen)+viewmin
- if dotstart == 2: dotstart=1
- dotend=int(screen*(eofs+1)/modlen)+viewmin-1
- if modeofs - viewmin == 0: modeofs=2
- selindicator=dotstart + int( (dotend - dotstart + 1) * (selected - viewmin) / (modeofs - viewmin +1) )
- except ZeroDivisionError:
- dotstart=1
- dotend=1
- selindicator=1
- if selindicator > eofs: selindicator=eofs
- if dotend < dotstart: dotend=dotstart
- wrapextralineuse=0
- #lineuse=0
- output=[]
- if not viewmax:
- viewrange=range(viewmin, viewmin+screen+1)
- else:
- below_max=viewmax-screen
- if below_max < 0: below_max=0
- viewrange=range(below_max, viewmax+1)
- for i in viewrange:
- #lineuse+=1
- outline="\x1b[m"
- if i<dotstart or i>dotend:
- scrollbar=" "
- elif i == selindicator:
- scrollbar="X "
- else:
- scrollbar="* "
- outline+=scrollbar
- try:
- try:
- preprune=filedict[i]["format"]
- except TypeError:
- preprune="\x1b[m"+filedict[i]
- list_of_prune=[]
- prunedline,prunedleft,leftover=cut_string(preprune, width-2)
- list_of_prune.append(outline+prunedline)
- if options.wraplonglines:
- while len(leftover) > 0:
- #if i+wrapextralineuse == viewmin+screen-1:
- # break
- wrapextralineuse+=1
- #prunedline+="\n"
- newpl,prunedleft,leftover=cut_string(leftover, width-11)
- # prunedline+=" "*(width-col_count(newpl)-2)+newpl
- list_of_prune.append(scrollbar+" "*(width-col_count(newpl)-2)+newpl)
- prunedleft=0
- if i == selected:
- list_of_prune[-1]+="\x1b[36;46m"
- while prunedleft > 0:
- prunedleft-=1
- list_of_prune[-1]+="#"
- for counter in range(len(list_of_prune)):
- list_of_prune[counter]=list_of_prune[counter].replace("\x1b[m","\x1b[m\x1b[30;46m")
- list_of_prune[-1]+="\x1b[m"
- output.append(list_of_prune)
- except IndexError:
- output.append([outline])
- i=0
- wrapextralineuse=0
- lineuse=0
- done=True
- if not viewmax:
- for counter in output:
- i+=len(counter)
- if i>original_screen+1:
- wrapextralineuse+=1
- i-=len(counter)
- if len(counter) > 1: wrapextralineuse+=1
- done=False
- break
- wrapextralineuse+=len(counter)-1
- sys.stderr.write("\n".join(counter)+"\n")
- if done: wrapextralineuse=0
- return(wrapextralineuse, 0, i)
- else:
- for index in reversed(range(len(output))):
- i+=len(output[index])
- if i>original_screen+2:
- i-=len(output[index])
- index+=1
- done=False
- break
- for counter in output[index:]:
- wrapextralineuse+=len(counter)-1
- sys.stderr.write("\n".join(counter)+"\n")
- if done: wrapextralineuse=0
- return(0, wrapextralineuse, i)
- def erase_filelist(screen):
- for unused in range(screen):
- sys.stderr.write("\x1b[2K\x1b[A")
- sys.stderr.write("\x1b[2K\r")
- def unfixshell_singlequote(goodstr):
- badstr=re.sub("'\\\\''", "'", goodstr)
- if badstr[-1] == "'":
- return badstr[1:-1]
- else:
- return badstr[1:]
- def unfixshell(goodstr):
- if len(goodstr) != 0 and goodstr[-1] == "\\":
- appendslash="\\"
- else:
- appendslash=""
- goodpieces=[]
- while "\\\\" in goodstr:
- index=goodstr.index("\\\\")
- goodpieces.append(goodstr[:index])
- try:
- goodstr=goodstr[index+2:]
- except IndexError: goodstr=""
- goodpieces.append(goodstr)
- goodstr=""
- for piece in goodpieces:
- goodstr=goodstr+re.sub("\\\\","",piece)+"\\"
- return goodstr[:-1]+appendslash
- def fixshell(badstr):
- badchars=""" !@#^&*()`'"<>\\[]{};:=?| """ #$ is done above only in specific cases
- goodstr=""
- prev=""
- for ch in badstr:
- if ch in badchars:
- ch="\\"+ch
- goodstr=goodstr+ch
- return re.sub("\\\\\\\\\$","\\$",goodstr) #Turn \\$ into \$
- def cut_string(line, width):
- #Thanks to:
- #http://bugs.python.org/file14782/test_ucs2w.py
- newline=""
- wait_for_m=False
- leftover=""
- count=0
- gc.disable()
- for ch in line: #line.decode("utf8"): #filesystem encoding?
- if wait_for_m:
- newline+=ch
- if ch == 'm':
- wait_for_m=False
- continue
- if ch == '\x1b':
- wait_for_m=True
- newline+=ch
- continue
- if ch == "\n":
- ch="?"
- if ch == "\t":
- if count +2 + 8 > width: break #+2 for scrollbar
- newline+=" "*(8-(count+2)%8)
- count+=8-(count+2)%8
- continue
- if east_asian_width(ch) in "WF":
- count+=1
- count+=1
- if not count > width:
- newline+=ch
- else:
- leftover+=ch
- gc.enable()
- #return newline.encode("utf8"),width-count
- return newline, width-count, leftover
- def col_count(line):
- wait_for_m=False
- count=0
- gc.disable()
- for ch in line:
- if wait_for_m:
- if ch == 'm':
- wait_for_m=False
- continue
- if ch == '\x1b':
- wait_for_m=True
- continue
- if ch == '\t':
- count+=8-(count+2)%8
- continue
- if east_asian_width(ch) in "WF":
- count+=2
- continue
- count+=1
- gc.enable()
- return count
- def isrecommended(cmd, file, isdir):
- if cmd in ("cd","popd","rmdir"):
- return isdir
- # http://wiki.archlinux.org/index.php/Common_Applications
- # http://wiki.archlinux.org/index.php/Lightweight_Applications
- # not sure if some of the binaries are correctly named
- #Video (and audio)
- if cmd in ("mplayer", "mwrap", "vlc", "gmplayer", "smplayer", "mencoder", "kmplayer", "Parole", "whaawmp", "dragonplayer","ffmpeg"):
- return re.search("\.(mkv|m4v|mpe?g|avi|mp.|wmv|rmvb|as[fx]|divx|vob|ogm|rm|flv|part|iso|mp?|ogg|wav|flac|m4a)$",file,re.I) != None
- #Audio
- if cmd in ("mpg123", "mpg123s", "mpg321", "mp3blaster", "cmus", "cplay", "moc", "xmms", "xmms2", "sonata", "deadbeef","ogg123","mnama"):
- return re.search("\.(mp.|aac|wav|ogg|gsm|dct|flac|au|aiff|vox|wma|aac|ra|m4a)$",file,re.I) != None
- #PDF
- if cmd in ("xpdf","epdfview","evince","foxit","mupdf","okular","apvlv","zathura"):
- return re.search("\.pdf$",file,re.I) != None
- #Images
- if cmd in ("feh","geeqie","gqview","eog","gpicview","gthumb","mirage","qiv","ristretto","xnview","xv","viewnior"):
- return re.search("\.(jpe?g|png|gif|tiff|bmp|ico?n|tif)$",file,re.I) != None
- #Games
- if cmd in ("sdlmame","openmsx","msxplay","zsnes","desmume","VirtualBoy"):
- return re.search("\.(rom|dsk)$",file,re.I) != None
- #Wine
- if cmd in ("wine", "winewrap", "wineconsole"):
- return re.search("\.(exe|com|bat)$", file, re.I) != None
- #Archives
- if cmd in ("atool","x","xi","gunzip","extract","unzip","unrar","zip","rar","7z", "comix", "v"):
- return re.search("\.(tgz|zip|rar|bz2|gz|tar|exe|pk3|lha|Z|lzma)$",file,re.I) != None
- #Text
- if cmd in ("vim","nano","acme","beaver","geany","leafpad","medit","mousepad","pyroom","sam","vi","gvim","emacs","tea","scite"):
- return re.search("\.(pdf|rom|dsk|jpe?g|png|gif|tiff|bmp|ico?n|tif|pdf|wav|ogg|gsm|dct|flac|au|aiff|vox|wma|aac|ra|mkv|mpe?g|avi|mp4|wmv|rmvb|as[fx]|divx|vob|ogm|rm|flv|part|iso|mp.|tgz|zip|rar|bz2|gz|tar|exe|pk3|lha|Z|lzma|\.o)$",file,re.I) == None and not isdir #everything else
- return False
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement