Notepad++ Automatic Detection of Python Tabs or Spaces - python

I normally write code with tabs but many python libraries use spaces. Is there any way for Notepad++ to automatically detect how the file is formatted and have it automatically switch to using spaces when the file is already formatted that way?
BTW, I know there was already an SO question on how to change Notepad++'s tab format. But it would be better if it automatically changed based on the current file's formatting.

If you install the "Python Script" plugin for Notepad++, you can write code to automatically switch between tabs and spaces.
Here's how:
In the menu: Plugins -> Python Script -> Configuration, and set Initialization to ATSTARTUP. When Notepad++ starts, the startup.py script will run.
Find startup.py and edit it. On my PC its path is c:\Program Files\Notepad++\plugins\PythonScript\scripts\startup.py, add the following code to startup.py.
The function buffer_active() is called every time when you switch tab, and guess_tab() checks whether the text is using tab indent or not. You can show the Python console to debug the code.
def guess_tab(text):
count = 0
for line in text.split("\n"):
indents = line[:len(line)-len(line.lstrip())]
if "\t" in indents:
count += 1
if count > 5:
return True
else:
return False
def buffer_active(arg):
editor.setBackSpaceUnIndents(True)
use_tab = guess_tab(editor.getText())
editor.setUseTabs(use_tab)
sys.stderr.write( "setUseTabs %s\n" % use_tab )
notepad.clearCallbacks([NOTIFICATION.BUFFERACTIVATED])
notepad.callback(buffer_active, [NOTIFICATION.BUFFERACTIVATED])
This is only an example, feel free to make guess_tab() better yourself, maybe use a global dict to cache the result and speedup the callback function.

Here is an improved version based on HYRY's answer :
Works on the startup tab (when you launch notepad++ to open a file)
Doesn't need a minimal amount of rows to trigger indentation detection. Indentation guess is based on the first encountered indented line.
Keeps indentation defaults when indentation cannot be detected
Very efficient, doesn't slow down Notepad++ when opening big files (tested on a 220 MB file, indentation detection takes only < 300 ms)
Available for download here : https://gist.github.com/vincepare/8a204172d959defb2122
import re
import time
def indent_guess_tab(text):
for line in text.split("\n"):
pattern = re.compile("^( {4,}|\t)")
match = pattern.match(line)
if (match):
return True if ("\t" in match.group(1)) else False
def indent_auto_detect(arg):
start = time.clock()
# Get text sample
maxLen = 500000
len = editor.getTextLength()
len = len if len < maxLen else maxLen
sample = editor.getTextRange(0, len)
# Indent set
current_use_tab = editor.getUseTabs()
use_tab = indent_guess_tab(sample)
if (use_tab != None and use_tab != current_use_tab):
console.write("Indent use tab switch (%s => %s)\n" % (current_use_tab, use_tab))
editor.setUseTabs(use_tab)
end = time.clock()
console.write("Indentation detection took %s ms\n" % (round((end-start)*1000, 3)))
notepad.clearCallbacks([NOTIFICATION.BUFFERACTIVATED, NOTIFICATION.READY])
notepad.callback(indent_auto_detect, [NOTIFICATION.BUFFERACTIVATED])
notepad.callback(indent_auto_detect, [NOTIFICATION.READY])
console.write("Automatic indentation detection started\n")
indent_auto_detect(None)

Nope!
You can always just change them (to tabs, of course) to suit your needs with Replace All ( , \t) in extended mode.

Related

How does this older, open source .py script differ in language syntax from the latest python 3.0 or greater?

I am fresh meat in the coding world and am diving head-first into python as we speak, so I apologize for such a rookie question in advance. But basically, I got assigned this log parsing project for school and found a seemingly nice parsing script/template online which I thought could be great for me to use. However, after looking at some of the syntax, it became apparent that it was written in an older version of python. Since I only started learning python a few weeks ago, I am not confident in understanding what syntax needs to change, if any, and if it is properly constructed like I initially assumed. My main question is, after viewing the script below, what statements, methods, variables, functions, ect., do you think must be (or should be) changed in order for me to get the ball rolling?
I'm running Win10 and using Spyder (from Conda) with python version 3.7.
I'd post the website link to this code but I don't know the rules on posting links in questions! However, if you search for 'pythonicways' you'll find it, as well as a walk-through guide for why it was made the way it was by the creator.
import time
from time import strftime
def main():
log_file_path = r"C:\ios logs\sfbios.log"
export_file_path = r"C:\ios logs\filtered"
time_now = str(strftime("%Y-%m-%d %H-%M-%S", time.localtime()))
file = "\\" + "Parser Output " + time_now + ".txt"
export_file = export_file_path + file
regex = '(<property name="(.*?)">(.*?)<\/property>)'
parseData(log_file_path, export_file, regex, read_line=True)
def parseData(log_file_path, export_file, regex, read_line=True):
with open(log_file_path, "r") as file:
match_list = []
if read_line == True:
for line in file:
for match in re.finditer(regex, line, re.S):
match_text = match.group()
match_list.append(match_text)
print match_text
else:
data = file.read()
for match in re.finditer(regex, data, re.S):
match_text = match.group();
match_list.append(match_text)
file.close()
with open(export_file, "w+") as file:
file.write("EXPORTED DATA:\n")
match_list_clean = list(set(match_list))
for item in xrange(0, len(match_list_clean)):
print match_list_clean[item]
file.write(match_list_clean[item] + "\n")
file.close()
if __name__ == '__main__':
main()
I'm not expecting anything in particular, per se. I just want to know what changes must be or should be made to this template/script. My overall goal is to open & read a .log file, parse it for several various capture groups using regex, store them all in some variables or some sequence type, and then extract that information onto a new .txt file (preferably in CSV format, or some other tabular delimited format)
You should be able to just change the print lines to get this going.
# print match_text
print(match_text)
#####
#print match_list_clean[item]
print(match_list_clean[item])
Also, try running it first next time. Get used to reading traceback (error messages). You can learn a lot from them.
This is Python 2. Use the standard library module lib2to3 to convert it to Python 3. That will be far better than trying to update the code manually, particularly as you aren't proficient in either version of Python.

Process vi yank buffer with python

I would like to add a key map to VI. The idea is to yank text and pass it to a python code.
Subsequently this python code can be used to preform some manipulations on the yanked text contained in the buffer #"
To do so, I added the following line to .vimrc
:map <F2> :echo system("python /tmp/t.py ".shellescape(#")) <Enter>
By pressing F2 the python script would run the code with #" as input. The problem is, that the yanked buffer contains the end line \ is a column is yanked with <C-r>V.
The buffer looks like this for a column input
1.233\
1.111\
1.222
I would like to accomplish the following
1) Don't include \ in the yank buffer is possible
2) make the pyhon script globally visible from within VI. Right now, it has to be in the same folder as the VI file, or an absolute path is needed
The latter one can be properly done by placing the script in the python site packages and importing it, but I guess, that more knowledgeble people might have better ideas. I remember seeing this done, by putting the python script in a special Vi folder.
the python code:
import sys
def to_float(v):
if len(v)>0 and v != "":
try:
return float(v)
except ValueError:
#print('yanked wrong text 1 "%s" '%v)
try:
return float(v[:-1])
except ValueError:
#print('yanked wrong text 2 "%s" '%v)
return 0.
else :
return 0.
def func(v):
s=0.
for i in v[1].split():
#print('from py >> %s <<'%i)
s=s+to_float(i)
print(">>>Summ: %17.8E"%s)
func(sys.argv)
Python-inside-Vim (as long as it is properly set up). Just dump this into your .vimrc (and make sure you don't add any indent to anything between python and EOF):
python << EOF
import vim
def float_or_0(value):
try:
return float(value)
except:
return 0.0
def sum_column():
lines = vim.eval('#"').splitlines()
total = sum(float_or_0(x) for x in lines)
print(">>>Summ: %17.8E" % total)
EOF
xmap <F2> y:py sum_column()<Enter>
Select your column, and hit F2. Magic. No hassle with transfering text through shell command line.
Or, you could select one of the strategies from Quickly calculate the total of a column of numbers.

Use Vim Retab to solve TabError: inconsistent use of tabs and spaces in indentation?

Apologize for the newbie question, but I have read the manual, this question, and tried several times without results I expected.
So I was using vim to edit a file (attached). But when running, I got the TabError: inconsistent use of tabs and spaces in indentation error.
Here is what I have tried:
Open the file with Vim. type :retab, and :x. Run the file again. Still got the TabError message.
Open the file again and type :retab! and :x. Run the file again. Still got the TabError message.
Open the file again and type :retab! 4 and :x. Run the file again. This time it works but I have no idea why? Plus, in the files indentation seems excessively long. (I read here that the editor might display 8 spaces for a tab)
My questions are:
What does :retab, :retab!, and :retab! 4 mean?
Why doesn't :retab work on my file?
#!/usr/bin/env python
#Reduce function for computing matrix multiply A*B
#Input arguments:
#variable n should be set to the inner dimension of the matrix product (i.e., the number of columns of A/rows of B)
import sys
import string
import numpy
#number of columns of A/rows of B
n = int(sys.argv[1])
#Create data structures to hold the current row/column values (if needed; your code goes here)
currentkey = None
alist = [] # list for elelents in A
blist = [] # list for elements in B
# input comes from STDIN (stream data that goes to the program)
for line in sys.stdin:
#Remove leading and trailing whitespace
line = line.strip()
#Get key/value
key, value = line.split('\t',1)
print(key, value)
#Parse key/value input (your code goes here)
key = (key.split(',', 1)[0], key.split(',',1)[1])
value = (value.split(',', 1)[0], value.split(',',1)[1], value.split(',',1)[2])
#If we are still on the same key...
if key==currentkey:
#Process key/value pair (your code goes here)
# store all values in a lisl
if value[0]=='A':
alist.append([value[1], value[2]])
else:
blist.append([value[1], value[2]])
#Otherwise, if this is a new key...
else:
#If this is a new key and not the first key we've seen, i.e. currentkey!=None
if currentkey:
#compute/output result to STDOUT (your code goes here)
alist = sorted(alist)
blist = sorted(blist)
newlist = [a[1]*b[1] for a,b in zip(alist, blist)]
res = newlist.sum()
print(currentkey, res)
currentkey = key
#Process input for new key (your code goes here)
Just type :help retab in Vim and read. I think I can't explain it better than the help. Maybe you are missing the optional range part; use % prefix to apply to the whole file. Also useful is :set list to show you every chars; this will show you the tabs and line ends (disable with :set nolist) and :set <name> with no value to see the current value, ex : set tabstop or followed by some value to set.
By showing all chars, enabling and disabling expansion of tabs into spaces with :set expandtab and :set noexpandtab, setting tabstop and by using for ex. :retab! 4 you can play your way around and switch from tabs only and spaces only, and change the tab column width.
This link, vim settings for python might be useful also
Esc
:%s/\t/ /g
It means to replace the tab with 4 spaces. Hit Enter
Esc
:wq
While just trying to run :retab might not work if you have copy pasted code and started to edit it.
You can try setting the vim/vi settings first:
Check if you have ~/.vim/vimrc file else run sudo mkdir ~/.vim && sudo touch ~/.vim/vimrc to create settings file
once created edit vimrc to add below snippet
set softtabstop=4
set tabstop=4
set shiftwidth=4
set expandtab
open your file using vim/vi and run :retab

How can I prevent ANSI escape sequences in my Python script from messing with my zsh RPROMPT and cursor positions?

I've been working on a Python script that generates an RPROMPT for zsh about the state of a git repo in the current working directory. It's invoked in my .zshrc file with:
RPROMPT='$(python3 ~/.git_zsh_rprompt.py)'
To differentiate it from the other text in my terminal, I've used ANSI escape codes to make it bold and color it based on whether the repo is clean or dirty. For whatever reason, adding these escape codes has caused my RPROMPT to scoot over to the left, and it has also moved my cursor over on top of my left PROMPT. Here's a representation, with the block representing my cursor:
jared#Jareds-Mac⌷ook-Pro:foobar% master( +2 ~4 )
Aside from a few non-educated guesses, I'm not entirely sure why this is happening. I'm hoping someone here does and is aware of a solution or workaround that's puts everything back where it's supposed to be. For reference, here is the offending script:
from collections import Counter
from os import devnull
from subprocess import call, check_output, STDOUT
def git_is_repo():
command = ["git", "branch"]
return not call(command, stderr = STDOUT, stdout = open(devnull, "w"))
def git_current_branch():
command = ["git", "branch", "--list"]
lines = check_output(command).decode("utf-8").strip().splitlines()
return next((line.split()[1] for line in lines if line.startswith("* ")),
"unknown branch")
def git_status_counter():
command = ["git", "status", "--porcelain"]
lines = check_output(command).decode("utf-8").strip().splitlines()
return Counter(line.split()[0] for line in lines)
if __name__ == "__main__":
if git_is_repo():
counter = git_status_counter()
# Print bold green if the repo is clean or bold red if it is dirty.
if counter.elements() == []:
print("\033[1;32m", end="")
else:
print("\033[1;31m", end="")
print(git_current_branch(), end="")
# Only print status counters if the repo is dirty.
if counter.elements() != []:
print("(", end="")
if counter["??"] != 0:
print(" +{}".format(counter["??"]), end="")
if counter["M"] != 0:
print(" ~{}".format(counter["M"]), end="")
if counter["D"] != 0:
print(" -{}".format(counter["D"]), end="")
print(" )", end="")
# Reset text attributes.
print("\033[0m", end="")
You want to use the %{ %} ZSH escape sequence around your ANSI escapes in the prompt, as documented here
%{...%}
Include a string as a literal escape sequence. The string
within the braces should not change the cursor position. Brace pairs
can nest.
A positive numeric argument between the % and the { is treated as
described for %G below.
This is the usual problem with zsh, like all other shells, not knowing how long your prompt is except by strlening the string, unless you tag the non-printing characters for it in some way.
There are ways to work around this for every shell,* but in zsh, you really don't have to; that's half the reason it has visual effects commands in its prompt format in the first place.**
So, for example, instead of this:
print("\033[1;32m", end="")
… you can do this:
print("%B%F{green}", end="")
zsh knows how to look up bold and green and insert the appropriate escape sequences for your terminal, and it knows now to count those sequences against your prompt length.
* IIRC, zsh supports the bash-style escaped square brackets, and its own %{…%} tagging.
** The other half is that the visual effects will termcaps to the right escape sequences, or degrade to nothing if that's not possible, instead of just assuming everything is ANSI.

Terminal screen coordinates in python

I'm newbie in using curses lib. I want to make a python program (running in a DOS terminal) that can return the cursor to the start of the current line allowing subsequent output to overwrite what was previously written there. I tried to call a shellscript from python to do it, but I beleive it may exist a better way for doing it.
If all you want to do is rewrite the current line, just print a return char "\r". For example, this prints "ABCdef":
# print 'abcdef' then backup to start of line, then print 'ABC'
# (then print the normal cr/lf that 'print' always does)
print "abcdef\rABC"
(Also helpful to know that you can suppress the cr/lf by ending your print with a trailing comma...)
.

Categories

Resources