probleme with old python scrip - python
I'm still republishing a python 2.x script in 3.x.
at some point, the script must replace the "print" function with "disp" (equivalent in TI basic language) except that it no longer works because of parentheses. anyone have an idea to fix it?
The code :
elif (line.find("print ")==idepth(line)):
line = replace(line,"print ","Disp ")
if (line[-1] == ","):
line = line[:-1].rstrip() # Trailing , not legal for ti basic
thanks in advance
Edit: full code :
import sys
import os
import re
#GUI:
import tkinter as tk
from tkinter import filedialog
import tkinter.simpledialog
import tkinter.messagebox
GUI_MODE = False
TAB_REPLACE = " "
def main():
args = sys.argv[1:]
global GUI_MODE
print (args)
if (len(args)==0):
GUI_MODE=True
root = tk.Tk()
root.withdraw()
inp = filedialog.askopenfilename(title="Select a python script to convert")
if (inp==''):
print ("cancelled")
return 0
else:
inp=args[0]
#now input file is known
file=open(inp)
prog = file.read().replace("\r","").split("\n") # Lines of code
#Get a program name:
if (prog[0][:1]=="#" and (prog[0].upper().find("NAME:")>-1 or prog[0].upper().find("PROGRAM:")>-1 )):
outname=prog[0][prog[0].find(":")+1:]
else:
outname=tkinter.simpledialog.askstring("File name","What do you want to name this program?")
fixed = format(prog)
#Write the converted program in this folder:
print ("\n--Converted to TI-Basic code:--")
print (fixed)
print ("")
print ("Making output files: "+outname+".tib, "+outname+".8xp ...")
#Write the converted program in this folder:
outfile=open(outname+".tib","w")
outfile.write(fixed)
outfile.close()
#Write the .8xp program
outfile=open(outname+".8xp","w")
outfile.write(fixed)
outfile.close()
#assuming the compiler tibasic.exe is in this folder:
if (sys.platform[:3]=="win"):
if (os.system('tibasic.exe '+outname+'.tib')): #Returns non-0, error:
errReport("Error trying to run tibasic.exe! Make sure it is in the current folder.")
else:
if (os.system('wine tibasic.exe '+outname+'.tib')): #Returns non-0, error:
errReport("Error trying to run tibasic.exe! Make sure it is in the current folder, and w.i.n.e is installed.\n"+
"(See http://www.winehq.org/ for installer)")
os.remove(outname+".tib")
a=input("Done! Press enter to exit:") #pause
return 0
def format(linesArray): #converts lines from Python to ti-basic.
for i in range(len(linesArray)):
linesArray[i]=linesArray[i].replace("\t",TAB_REPLACE) #Important! see idepth()
i=0;
linesArray.append("") # 0-indent ending so blockAddEnd won't mess up.
while (i<len(linesArray)):
#Convert control blocks (if, for, while) from indented (python) to END (TI)
line = linesArray[i]
if isBlockStart(line,"for "):
linesArray = blockAddEnd(linesArray, i, "End")
elif isBlockStart(line,"if "):
linesArray = blockAddEnd(linesArray, i, "End")
elif isBlockStart(line,"while "):
linesArray = blockAddEnd(linesArray, i, "End")
elif isBlockStart(line,"repeat "): #not in python, but works on TI.
linesArray = blockAddEnd(linesArray, i, "End")
i+=1
# Don't need indentations anymore, do the rest of the conversions:
for i in range(len(linesArray)):
linesArray[i]=convLine(linesArray[i],i+1)
#Remove blanks:
for i in range(linesArray.count("")):
linesArray.remove("")
return "\n".join(linesArray)
def convLine(line,num): #Line by line conversion.
line = line.rstrip().lstrip() #trim indentation.
lnum = "Line "+str(num)+": "
if line.count("#"):
comment = line[line.find("#"):]
if (comment[0:6] == "#no-ti"):
#Does not work on the ti.
return ""
elif (comment[0:4] == "#ti:"):
# Only for ti:
return comment[4:]
else:
line = line[:line.find("#")] # take comment off code
#No imports in ti-basic!
if line.startswith("import ") or (line.count(" import ") and line.startswith("from ")):
return ""
#Errors and warnings:
if (toolong(line)):
print (lnum+"Warning: Text string too long to fit on a TI83/84 screen. The calculator screen is 16 characters wide, 8 characters high.")
if (line.find("\n")>-1):
print (lnum+"Warning: newline \\n is not allowed in TI-Basic.")
if (line.find("'''")>-1):
print (lnum+"Warning: ''' quotes are not allowed, you must use \" quotes on a single line for TI-Basic.")
if (replace(line,"pow(","")!=line):
errReport(lnum+"TI calculators don't have the pow() command, you must use a**b instead of pow(a,b).")
if (replace(line,"import ","")!=line):
print (lnum+"import ignored. No import statements in TI-Basic!")
return "" # ignore import statements!
if (replace(line,"-=","")!=line):
errReport(lnum+"The -= operator is not allowed.\nTry +=- or a=a+-number instead.")
if (replace(line,"def ","")!=line):
errReport(lnum+"Functions are not supported in TI-Basic! However, you can run another program with \"prgmPRGNAME\".")
if (replace(line,"//","")!=line):
print (lnum+"// division converted to / division: For int division, try int(a/b).")
line=replace(line,"//","/")
if (replace(line,"-","")!=line):
print (lnum+"Warning: The - is changed to negative sign on the calculator. If you wanted to subtract, use a+-b instead of a-b.")
if (replace(line,"open(","")!=line):
errReport(lnum+"Error: TI calculators can't use \"open(filename)\" in programs. To store text, try using variables STR0, STR1, ... STR9.")
if (replace(line,"%","")!=line):
errReport(lnum+"Error: TI83/84 calculators don't have Mod.\n Instead of a % b, try (a/b-int(a/b))*b instead.")
# Replace excess spaces, they cause errors in the calculator:
line=replace(line,", ",",")
line=replace(line," + ","+")
line=replace(line," - ","-")
line=replace(line," +- ","+-")
line=replace(line," * ","*")
line=replace(line," / ","/")
line=replace(line," == ","==")
line=replace(line," > ",">")
line=replace(line," < ","<")
line=replace(line," != ","!=")
#TODO: Arrays converted to lists?
line=replace(line,"theta","[theta]") # variable
line=replace(line,"**","^")
line=mathReplace(line)
#round, max, min already works.
line=replace(line,"float(","(")
line=replace(line,"len(","dim(")
line=replace(line,"math.pi","[pi]")
line=replace(line,"math.e","[e]")
line=replace(line,"eval(","expr(")
line=replace(line,"-","[neg]") # use +- instead of - operator.
line=replace(line,"==","=")
line=replace(line," and ","&")
line=replace(line," or ","|")
line=replace(line,"random.random()","rand")
line=replace(line,"random.randint","RandInt")
line=replace(line,"int(","iPart(")
if (replace(line,"input(","") != line):
line=inputConv(line,num)
if isBlockStart(line,"for "):
line=forConv(line,num)
elif (isBlockStart(line,"if ")):
line = replace(line,"if ","If ")
line = replace(line,":",":Then")
elif (isBlockStart(line,"while ")):
line = replace(line,"while ","While ")
line = replace(line,":","")
elif (isBlockStart(line,"repeat")):
line = replace(line,"repeat","Repeat")
line = replace(line,":","")
elif (isBlockStart(line,"else")):
line = replace(line,"else:","Else")
elif isBlockStart(line,"elif"):
errReport(lnum+"""Error: There is no else-if command on the TI83/84. However, you can use this instead:
if <condition>:
...
else:
if <condition>:
...
else:
...""")
elif (line.find("print ")==idepth(line)):
line = re.sub(r"print *\((.+)\)", r"disp \1", line)
if (line[-1] == ","):
line = line[:-1].rstrip() # Trailing , not legal for ti basic
elif (replace(line,"=","")!=line): #assignment is -> on the calculator.
eqspace = line.find("=")
line = line[eqspace+1:].rstrip().lstrip() + "->" + line[:eqspace].rstrip().lstrip() # sto arrow.
line = fixEQ(line)
return replace(line,"+[neg]","-") #lastly, switch back the negative.
def fixEQ(line):
# fix +=, *=, /=.
# A+=1 changes to 1->A+, so fix it now.
if (line[-1]=="+" or line[-1]=="*" or line[-1]=="/"):
line = line[:-1].rstrip()+line[-1] # remove any spaces in "a +" etc
pre = line[line.find("->")+2:]
#pre = pre[:-1].rstrip()+pre[-1]
line= pre + "("+line[:line.find("->")]+")"+ line[line.find("->"):-1]
return line
def inputConv(line,num):
lnum = "Line "+str(num)+": "
if (replace(line,"raw_input(","")!=line and line==replace(line,"=","")):
#raw_input not assigned to variable is like Pause.
return "Pause "
else:
var = line[:line.find("=")].rstrip().lstrip()
if (len(var)>1 and var!="theta"): # might be invalid.
print (lnum+"Warning: Program tries to store to variable \"%s\"." % var)
prompt = line[line.find("input(")+6:]
prompt = prompt[:prompt.find(")")]
# Now return the TI basic input with var spaces removed:
return "Input "+prompt+","+var
def forConv(line,num):
lnum = "Line "+str(num)+": "
# split "for i in range(...):"
var = line[line.find("for ")+4:line.find(" in range")]
#print var
part = line[line.find("in range(")+9:] # only "...) : "
part = part.rstrip(": ")[:-1] # remove extra " " or ":", remove last ).
#print "'"+line+"'"
out = part.split(",")
if len(out)==1:
return "For(%s,0,(%s)-1)" % (var, out[0])
elif len(out)==2:
return "For(%s,(%s),(%s)-1)" % (var, out[0], out[1])
elif len(out)==3:
return "For(%s,(%s),(%s)-1,(%s)" % (var, out[0], out[1], out[2])
else:
errReport(lnum+"Too many commas in for loop!")
return "couldn't convert: "+line
def blockAddEnd(lines, startLine, endText):
# Takes an array, line #, and end text.
# Adds end for that indentation block.
startInd = idepth(lines[startLine])
if idepth(lines[startLine+1]) <= startInd:
errReport("Expected indent after line "+str(startLine+1)+".")
i = startLine+1
#continue searching for the end while it's indented or it's an else line:
while idepth(lines[i]) > startInd or (isBlockStart(lines[i],"else")):
i+=1
# now insert.
lines.insert(i,endText)
return lines
def idepth(text):
# get indentation depth of line.
depth=0
line = text.replace("\t",TAB_REPLACE) #tab is 4 spaces.
while (line[:1]==" "):
line=line[1:]
depth+=1
return depth
def replace(text, changethis, tothis):
# replaces text, but not in quotes.
arr = text.split("\"")
for i in range(0,len(arr),2):
arr[i]=arr[i].replace(changethis, tothis)
return "\"".join(arr)
def toolong(text):
# checks for too long string:
arr = text.split("\"")
for i in range(1,len(arr),2):
#print arr[i]
if (len(arr[i]) > 16):
return True
return False
def parMatch(text,num): # given "(stuff()...()))", returns the parentheses block.
lnum = "Line "+str(num)+": "
for i in range(len(text)):
part = text[:i-1]
if (part.count("(")==part.count(")")):
return part[1:-1] #without outside parentheses.
errReport(lnum+"Invalid parentheses")
def isBlockStart(line, type):
# Check if the line is start of a <type> block.
# checks if it starts with <type>, and ends with ":".
# example: isBlockStart("for i in range(8) : ","for") is true.
return (line.find(type) == idepth(line) and line.rstrip(" ")[-1]==":")
def errReport(text):
print (text)
if (GUI_MODE):
root = tk.Tk()
root.withdraw()
tkinter.messagebox.showerror("Error",text)
sys.exit(1)
def mathReplace(line):
""" Replaces mathematical functions with ti basic functions. """
#Same function in both Python and TI-basic:
same = ["sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "asinh", "acosh", "atanh"]
line=replace(line,"math.sqrt(","[root]^2(")
line=replace(line,"math.fabs(","abs(")
for func in same:
line = replace(line,"math.%s(" % func,func)
line=replace(line,"math.log(","ln(")
line=replace(line,"math.exp(","e^(")
line=replace(line,"math.floor(","int(")
line=replace(line,"math.log10(","log(")
#same, but without "math." They might use
#from math import sqrt etc...
line=replace(line,"sqrt(","[root]^2(")
line=replace(line,"fabs(","abs(")
for func in same:
line = replace(line, "%s(" % func,func)
#(Redundant lines deleted)
line=replace(line,"log(","ln(")
line=replace(line,"exp(","e^(")
line=replace(line,"floor(","int(")
line=replace(line,"log10(","log(")
return line
if __name__ == '__main__': main()
it's the original code with changement propose below
You can use python's regular expression library to perform more advanced string matching and replacement than replace(). Specifically, re.sub(), which functions the same as replace() but takes regular expressions instead of simple strings.
Be sure to first import it with import re. You can then do the following:
elif (line.find("print ")==idepth(line)):
line = re.sub(r"print *\(\"(.+)\"\)", r"disp \1", line)
if (line[-1] == ","):
line = line[:-1].rstrip() # Trailing , not legal for ti basic
This will look for a string of the format "print("&1")" or "print ("&1")" and replace it with "disp &1", where &1 is the contents between the quotes.
Edit: You had initially specified that you wanted the output "without the quotes", but it seems you've edited that comment. If you want to include the quotes in the output, use this line instead:
line = re.sub(r"print *\((.+)\)", r"disp \1", line)
Related
Extract string between 2 delimiters
I'm trying to extract some words between two delimiters. It works for the files where the script find these delimiters, but for the others files, the code extract all of the file. Example: File 00.txt: 'bqukfkb saved qshfqs illjQNqdj iohqsijqsd qsoiqsdqs' File 01.txt: 'jkhjkl dbdqs ihnzqid Bad value okkkk SPAN sfsdf didjsfsdf' I want to open 2 or more files like these two and extract only words between: 'Bad Value' and 'SPAN'. My code works for the file 01.txt, but not for the 00.txt ( i think it's because it doesn't find the delimiters so he prints everything. How can i fix it ? def get_path(): #return the path of the selected file(s) root = Tk() i= datetime.datetime.now() day = i.day month=i.month root.filename = filedialog.askopenfilenames(initialdir = "Z:\SGI\SYNCBBG",title = "Select your files",filetypes = (("Fichier 1","f6365tscf.SCD*"+str(month)+str(day)+".1"),("all files",".*"))) root.withdraw() return (root.filename) def extraction_error(file): f=open(file,'r') file=f.read() f.close() start = file.find('Bad value') +9 end = file.find('SPAN', start) return(file[start:end]) paths=get_path() cpt=len(paths) for x in range(0,cpt): print(extraction_error(paths[x])) Output : saved qshfqs illjQNqdj iohqsijqsd qsoiqsdq okkkk So in this case i just want to extract 'okkkk' and not print ' saved....' for the other file. Thanks in advance for your help
In your extraction_error function, you may want to test if the two key words can be found: start = file.find('Bad value') # remove + 9 here, put it later end = file.find('SPAN', start) if start != -1 and end != -1: # test if key words can be found, -1 for not found: return(file[start+9:end]) else: return ""
You're printing out something, because you are adding 8 to the start variable. Find returns negative one if the string is not found. So what you end up doing is printing out the elements from [7:-1]. I would add an if statement before the print statement: start = file.find('Bad value') end = file.find('SPAN', start) if start != -1 and end != -1: print(file[start + 9: end])
string.find() return -1 if the argument is not found in the string, example: print "abcd".find("e") # -1 You can just check the result before the return: start = file.find('Bad value') + 9 end = file.find('SPAN', start) if start == -1 or end == -1: return '' # Or None return(file[start:end])
Using re: import re def get_text(text): pattern= r'.+(Bad value)(.+)(SPAN).+' r=re.match(pattern,text) if r!=None and len(r.groups()) == 3: print(r.groups()[1]) lines = [ 'jkhjkl dbdqs ihnzqid Bad value okkkk SPAN sfsdf didjsfsdf' ,'ghghujh'] for line in lines: get_text(line) Output: okkkk
How to change the color of sys.stdin synchronously?
I wrote a simple program that can be used as a theme for Python. The stdin's color is white, stdout's color is green and stderr's color is red. The program works fine but also what i want to do is, when the user type a keyword like "def", this keyword's color should be changed as like as typing "def" in Vim. I thought to use a keylogger in order to catch the keyboard. But still i haven't found a useful way to change the keyword colors synchronously. Please take a look at the codes and give me an idea. Any help is much appreciated. Codes: #!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys import colorama CODE = "" SIZE = 0 TAB = " " * 4 colorama.init(autoreset=False) sys.stdout.write(colorama.Fore.WHITE) while True: if SIZE >= 1: LINE = input("... {}".format(TAB * SIZE)) CODE += "{}{}\n".format(TAB * SIZE, LINE) if LINE == '': if SIZE == 0: try: sys.stdout.write(colorama.Fore.GREEN) exec(CODE) sys.stdout.write(colorama.Fore.WHITE) except BaseException as ERR: sys.stderr.write("{}{}\n".format(colorama.Fore.RED, ERR)) sys.stdout.write(colorama.Fore.WHITE) CODE = "" SIZE = 0 else: SIZE -= 1 continue elif LINE.endswith(":"): SIZE += 1 else: continue else: LINE = input(">>> {}".format(TAB * SIZE)) CODE += "{}{}\n".format(TAB * SIZE, LINE) if not LINE.endswith(":"): if LINE == "exit()" or LINE == "quit()": break elif LINE == "clear()": os.system("cls" if os.name == "nt" else "clear") CODE = "" try: sys.stdout.write(colorama.Fore.GREEN) exec(CODE) sys.stdout.write(colorama.Fore.WHITE) except BaseException as ERR: sys.stderr.write("{}{}\n".format(colorama.Fore.RED, ERR)) sys.stdout.write(colorama.Fore.WHITE) CODE = "" SIZE = 0 else: SIZE += 1
I finish my terminal as follow. Looks pretty! O(∩_∩)O哈哈哈~ To highlight def, I do this operation: ## Replace "def" with "colorful def" if line.endswith(":") and "def " in line: sys.stderr.write("\x1b[1A\x1b[2K" + tag + line.replace("def ","\033[92mdef\033[0m ")+"\n")
How to print number of characters based on terminal width that also resize?
Not sure if it's possible, but I was hoping to do something where I can print a hyphen for the width of the terminal on one line. If the window's width is resized, the amount of hyphens displayed would print accordingly.
This is a more elaborated version that allows printing whatever you want always according to the dimension of the terminal. You can also resize the terminal while nothing is being printed and the content will be resized accordingly. I commented the code a little bit... but if you need I can be more explicit. #!/usr/bin/env python2 import threading import Queue import time import sys import subprocess from backports.shutil_get_terminal_size import get_terminal_size printq = Queue.Queue() interrupt = False lines = [] def main(): ptt = threading.Thread(target=printer) # Turn the printer on ptt.daemon = True ptt.start() # Stupid example of stuff to print for i in xrange(1,100): printq.put(' '.join([str(x) for x in range(1,i)])) # The actual way to send stuff to the printer time.sleep(.5) def split_line(line, cols): if len(line) > cols: new_line = '' ww = line.split() i = 0 while len(new_line) <= (cols - len(ww[i]) - 1): new_line += ww[i] + ' ' i += 1 print len(new_line) if new_line == '': return (line, '') return (new_line, ' '.join(ww[i:])) else: return (line, '') def printer(): while True: cols, rows = get_terminal_size() # Get the terminal dimensions msg = '#' + '-' * (cols - 2) + '#\n' # Create the try: new_line = str(printq.get_nowait()) if new_line != '!##EXIT##!': # A nice way to turn the printer # thread out gracefully lines.append(new_line) printq.task_done() else: printq.task_done() sys.exit() except Queue.Empty: pass # Build the new message to show and split too long lines for line in lines: res = line # The following is to split lines which are # longer than cols. while len(res) !=0: toprint, res = split_line(res, cols) msg += '\n' + toprint # Clear the shell and print the new output subprocess.check_call('clear') # Keep the shell clean sys.stdout.write(msg) sys.stdout.flush() time.sleep(.5) if __name__ == '__main__': main()
Check this out:(it worked on windows and python3 ) import os os.system('mode con: cols=100 lines=40') input("Press any key to continue...") os.system('mode con: cols=1000 lines=400') input("Press any key to continue...")
This is doing exactly what you asked for... with a very small issue: when you make the shell smaller the cursor goes down of one line and the stuff that is above will stay there.... I can try to solve this issue... but the result will be more complicated. I assumed you are using a unix system. The code uses threads to be able to keep the line on the screen while doing other things. In this case just sleeping... Moreover, only using a thread is actually possible to have a "fast" answer to the change of the dimension of the terminal. #!/usr/bin/env python2 import threading import time import sys from backports.shutil_get_terminal_size import get_terminal_size def main1(): ptt = threading.Thread(target=printer2) ptt.daemon = True ptt.start() time.sleep(10) def printer2(): while True: cols, rows = get_terminal_size() line = '-' * (cols - 2) sys.stdout.write("\r" + '#' + line + '#') sys.stdout.flush() time.sleep(.5)
How to put text in input line: how to ask for user input on the command line while providing a 'default' answer that the user can edit or delete?
I am creating a Python script that asks for input from the command line. The user will have the ability to edit a part of a file. I can ask for the new information and overwrite it in the file, no problem. But I would rather have the to-edit part of the file already put in the command line, so it does not have to be typed completely over. Is this possible? File: 1|This file 2|is not empty Example: >>>edit line 2 Fetching line 2 Edit the line then hit enter >>>is not empty #This is written here by the script, not by the user Which then can be changed to >>>is not full either Edited file Afther which the file has changed to: 1|This file 2|is not full either I hope it's clear what I am trying to accomplish. This question has been said to answer my question, it does to a certain extent. It does when I am running Linux with readline. However, I am not. I am using Windows and am not using readline. I would like to only use the standard library. An answer for Windows is also provided with that question. However, I get an ImportError with win32console, it might be because mentioned question is not about Python3.4, but mine is. Also, I was wondering if this was possible with the standard library, not with an external library.
Unfortunately, I don't know if kind of input() with default value is available in standard library. There is an external solution - use win32console as mentioned in this answer. However, it has two pitfalls as far as I can see. First, the import is bundled in a package pywin32. So you would use pip install pywin32, except it does not work, because of the second pitfall: the information about the package at pypi is outdated, it says that package is incompatible with Python 3.4... But in fact, it can work! You should follow the "Download URL" visible at pypi project page (i.e. https://sourceforge.net/projects/pywin32/files/pywin32/ ) and install latest build. I just installed build 219 for Py3.4, as I myself also use this Python version. On the page installers are provided for several Python versions for 32bit and 64bit Windows. Also, I've tweaked the code from above-linked SO answer to work in Python 3: import win32console _stdin = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE) def input_def(prompt, default=''): keys = [] for c in str(default): evt = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT) evt.Char = c evt.RepeatCount = 1 evt.KeyDown = True keys.append(evt) _stdin.WriteConsoleInput(keys) return input(prompt) if __name__ == '__main__': name = input_def('Folder name: ', 'it works!!!') print() print(name) This works on my Windows machine... If this does not work on yours, can you provide the error message?
I have written a line editor which hopefully does what you are looking for. But it is a quick-and-dirty hack. It is Windows only and written with CPython 3.6.5 on Windows 10, so its use might be limited. It has been tested on codepage 1252 (ANSI Latin 1; Western European (Windows)) and codepage 65001 (utf-8). It is very basic and a bit sluggish as it is not speed-optimized. (I should rewrite it in C but I do not have the time.) It is hardly tested and poorly documented. import msvcrt import os import sys if os.name != 'nt': raise NotImplementedError('This module works only on MS Windows!') CTRL_00 = 0 CTRL_E0 = 224 KEY_BACKSPACE = 8 KEY_DELETE = 83 # CTRL KEY_END = 79 # CTRL KEY_ESC = 27 KEY_HOME = 71 # CTRL KEY_INSERT = 82 # CTRL KEY_LEFT = 75 # CTRL KEY_RETURN = 13 KEY_RIGHT = 77 # CTRL flush = sys.stdout.flush write = sys.stdout.write mode = ('[OVR]> ', '[INS]> ') # overwrite, insert prefix = len(mode[0]) def _update_line(insert, source, length, line, target): """Write a new line and position the cursor. source: previous cursor position length: old line length line: edited line target: next cursor position """ write('\b' * source) # set cursor to start of line write(' ' * length) # erase old line write('\b' * length) # again, set cursor to start of line write(mode[insert] + line[prefix:]) # write updated line write('\b' * (len(line) - target)) # set cursor to new position flush() # write buffer to screen def mswin_line_edit(default_string, insert=True): """Edit a MS Windows CLI line.""" insert = insert line = mode[insert] + default_string count = len(line) before = line[:count] after = line[count:] print(line, end='', flush=True) cursor = count while True: key = msvcrt.getwch() num = ord(key) if num == KEY_ESC: # abort edit return default_string if num == KEY_RETURN: # finish edit return line if num == KEY_BACKSPACE: # delete character before cursor if cursor > prefix: before = line[:cursor - 1] after = line[cursor:] line = before + after _update_line(insert, cursor, count, line, cursor - 1) cursor -= 1 count = len(line) elif num == CTRL_E0 or num == CTRL_00: # CTRL ctrl = ord(msvcrt.getwch()) if ctrl == KEY_END: # set cursor after last character if cursor < count: before = line after = '' _update_line(insert, cursor, count, line, count) cursor = count elif ctrl == KEY_HOME: # set cursor before first character if cursor > prefix: before = '' after = line _update_line(insert, cursor, count, line, prefix) cursor = prefix elif ctrl == KEY_LEFT: # move cursor 1 character to the left if cursor > prefix: before = line[:cursor] after = line[cursor:] _update_line(insert, cursor, count, line, cursor - 1) cursor -= 1 elif ctrl == KEY_RIGHT: # move cursor 1 character to the right if cursor < count: before = line[:cursor] after = line[cursor:] _update_line(insert, cursor, count, line, cursor + 1) cursor += 1 elif ctrl == KEY_DELETE: # delete character after cursor if cursor < count: before = line[:cursor] after = line[cursor + 1:] line = before + after _update_line(insert, cursor, count, line, cursor) count = len(line) elif ctrl == KEY_INSERT: # switch insert/overwrite mode insert ^= True _update_line(insert, cursor, count, line, cursor) else: # ordinary character before = line[:cursor] + key if insert: after = line[cursor:] else: after = line[cursor + 1:] line = before + after _update_line(insert, cursor, count, line, cursor + 1) cursor += 1 count = len(line) if __name__ == '__main__': test_string = input('test string: ') result = mswin_line_edit(test_string) print(f'\n{result}')
You could do it with tkinter: from tkinter import * def enter(): global commandEntry command = commandEntry.get() # Do stuff with command commandEntry.delete(0, END) def edit_line(line): global commandEntry commandEntry.insert(0, line) root = Tk() messageVar = StringVar() messageVar.set("Enter a command:") message = Label(root, textvariable=messageVar) commandEntry = Entry(root) enterButton = Button(root, text="Enter", command=enter) root.mainloop()
You should just have 2 variables: one for standard string, one for string that will user change by itself. Like: str1 = 'String that is standard' str2 = str1 #it usually will be standard string usr = input('your text goes here') if len(usr) != 0: str2 = usr #and here goes code for writing string into file
sublime plugin: find and select text
I got plugin for sublime text 3 that let me move cursor to line by its number: import sublime, sublime_plugin class prompt_goto_lineCommand(sublime_plugin.WindowCommand): def run(self): self.window.show_input_panel("Goto Line:", "", self.on_done, None, None) pass def on_done(self, text): try: line = int(text) if self.window.active_view(): self.window.active_view().run_command("goto_line", {"line": line} ) except ValueError: pass class go_to_lineCommand(sublime_plugin.TextCommand): def run(self, edit, line): # Convert from 1 based to a 0 based line number line = int(line) - 1 # Negative line numbers count from the end of the buffer if line < 0: lines, _ = self.view.rowcol(self.view.size()) line = lines + line + 1 pt = self.view.text_point(line, 0) self.view.sel().clear() self.view.sel().add(sublime.Region(pt)) self.view.show(pt) I want to improve it to let me move cursor to first line containing the specified string. It is like a search on file: For example if pass to it string "class go_to_lineCommand" plugin must move cursor to line 17 : and possibly select string class go_to_lineCommand. The problem is reduced to finding regionWithGivenString, and then I can select it: self.view.sel().add(regionWithGivenString) But don't know method to get regionWithGivenString. I tried to find on google: sublime plugin find and select text check api But still no result.
I am not sure about the typical way. However, you can achieve this in following way: Get the content of current doc. Search target string to find out its start and end position. Now you have the start and end point. Add the Region(start, end) to selections. Example: def run(self, edit, target): if not target or target == "": return content = self.view.substr(sublime.Region(0, self.view.size())) begin = content.find(target) if begin == -1: return end = begin + len(target) target_region = sublime.Region(begin, end) self.view.sel().clear() self.view.sel().add(target_region)
there you have it in the API, use the view.find(regex,pos) method. s = self.view.find("go_to_lineCommand", 0) self.view.sel().add(s) http://www.sublimetext.com/docs/3/api_reference.html
A possible improvement to the longhua's answer - adding moving cursor to the target line. class FindcustomCommand(sublime_plugin.TextCommand): def _select(self): self.view.sel().clear() self.view.sel().add(self._target_region) def run(self, edit): TARGET = 'http://nabiraem' # if not target or target == "": # return content = self.view.substr(sublime.Region(0, self.view.size())) begin = content.find(TARGET) if begin == -1: return end = begin + len(TARGET) self._target_region = sublime.Region(begin, end) self._select() self.view.show(self._target_region) # scroll to selection