New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite set-theme
to avoid file corruption
#9
Conversation
Hi, Thanks a lot for the patch. As for the new implementation, aren't we making a pretty big trade off here too? Now it scans the file line by line looking for matches to write and then it writes the changes as it finds the matches. I haven't used fileinput before. But the code looks like it might still be writing to the file multiple files? Does I also wonder if there's any readable patterns we can use to de-dupe the set up around using fileinput. Basically abstract the concept of using it to do inplace edits on a file and loop over each line. This way we only need to pass in what's being replaced. |
Hi Nick - thanks for considering my patch. Yes, As for de-duping, we can define something like this: def inplace_edit(file):
return fileinput.input(files=(file,), inplace=True) then use it like this: with inplace_edit(MYFILE) as f:
for line in f:
process(line) where |
Oh I see. So in the old case it's doing an open + close + [update content] + write + close and now it's just doing an open + close while 0 or more writes happen while it's open? And the corruption happens with the old code because that close event is happening twice and it's too quick for the MS terminal to deal with it due to the way it's listening for changes? It most likely does watch that config file because updating the config will have its effects take place within a reasonable amount of time (100-200ms). Are we still at a risk for corruption with the new code if the MS terminal happens to poll the file while it's open during the inplace_edit? |
There's no harm in doing: open ( The first write happens in this line: Line 199 in 42be51f
Line 128 in 42be51f
I believe Windows Terminal will open the file only after a writer closes it. As long as it does that, there should no longer be a risk for corruption. |
Thanks for the break down, it makes perfect sense now. Let's get this merged, but it may involve a few minor formatting changes, splitting up commits, etc.. I'll address these in a review on some of the lines over the next couple of days. I know some low hanging fruit will be adding 1 space between defining a variable and executing a block of code below it. There's also making that |
You're making this too easy haha. Those are really good. Btw do you have a TL;DR on |
Thanks 😄
|
One difference I noticed is: New version: if you run Although this has kind of a nice side effect of being able to run But I think maybe if there's no theme and no toggle-bg flag it should probably continue to throw an error. Hopefully this can be pulled off without complicating argparse too much. Also, I'm going to leave this thing in a 100ms Bash loop for the next hour and see if it corrupts anything. |
Thanks for the observation. I added a check which prints an error (with exit code 2) when no arguments are given. Another thing I noticed is that @@ -83,5 +83,5 @@ VIM_CONFIG = f'{HOME}/.vimrc'
-def edit_inplace(file):
+def edit_inplace(file, preserve_symlinks=True):
+ if preserve_symlinks:
+ file = os.path.realpath(file)
return fileinput.input(files=(file,), inplace=True)
|
The original kept the symlink in tact. Good catch tho, I didn't check for that in your version but I did have similar logic with the old Can you amend these commits: Feel free to amend 57c2df1 with your proposed For be4e66e it might be worth changing the argparse condition to check the length of In 48482bd I noticed you're using |
Right, passing a string to I amended 57c2df1 → 8f921e9 with my proposed I also pushed b932f9f to check the length of |
I think we can get by with just calling
It does hint about writing to stderr but maybe just passing a string to |
Could we use this newfound knowledge of Also, I'm not in a position to test this now but what does |
I called This makes the argument errors look more consistent:
|
Ok fair enough, let's keep it as is. Sometimes a bit of extra code is worth it to make the user experience better and more consistent. One last thing, in b932f9f you have |
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.error Edit: I also squashed some of the commits together to keep things organized |
Awesome thanks. I'll pull this down and give it a run through a bit later today and then merge it in if all goes well (it should). |
I know my merge window is closing, but I had a great idea to make the argument parser more helpful (3692310):
|
Oh wow, I didn't even know argparse did that out of the box. There's always time for deleting code. |
With d518236, the themes are also listed automatically:
|
About deleting code - I have to agree! I like to brag at work about my GitHub Enterprise stats - my deletions are roughly twice the amount of additions 😄 |
This PR deletes more code than adding it, so you're winning there considering how much better the script is now. Can you amend 3990482 by making the return and sys.exit lines be indented with 4 spaces instead of 2? It should pass running |
I think we're ready for a final test run / merge? |
def edit_inplace(file, preserve_symlinks=True): | ||
if preserve_symlinks: | ||
file = os.path.realpath(file) | ||
return fileinput.input(files=(file,), inplace=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an empty new line above the return statement to break it up from the if statement?
if match: | ||
bg = match.group(1) | ||
continue | ||
match = re.match('^colorscheme (.*$)$', line) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an empty new line above L98 to break up the condition and the 2nd match variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left a few minor recommendations on formatting.
Can you please amend the commits they are associated to?
I amended the commits to fix the formatting as you suggested. Please give this a final test - I have nothing more to add (or remove 🙂) |
It's all good. Thanks a lot for the patch and for making the overall PR experience as good as it gets. Edit: I've updated the documentation to reflect this update since the steps to customize it for different terminals have changed. I also updated my blog post to call out your PR at https://nickjanetakis.com/blog/a-terminal-tmux-vim-and-fzf-theme-switching-script-written-in-python#important-updates and pinned a comment in the YouTube video too https://www.youtube.com/watch?v=h509rn2xIyU. |
This avoids file corruption (which necessitated calling
sleep(1)
) by changing each file only once.With these changes,
set-theme --toggle-bg
should toggle the background for the active theme.These changes also reduces the memory usage, since only one line is read (and written) at a time.