Does anyone know of a way or a script that given a patch file can separate the whitespace changes from the functional changes?
Here's the issue. My project has strict whitespace style requirements and I have my editor set to enforce them. No tabs, No trailing spaces. My editor is set to automatically strip traiing spaces for example.
So, what inevitably happens is it's all good until I edit some third party code. I forget to turn off those oh-so-convenient features and then I get bitching from devs that the whitespace changes need to separated from the functional changes. So, 6 hours of editing code all has to get hand redone. No wonder so many bugs and features go unfixed when devs are more interested in 'rules' than 'results'. Okay, enough bitching.
Ideally I'd just run some script that would remove all whitespace changes from the patch and be done. Anyone know of such a feature?
Keep a copy of the original file, apply the patch and then diff again - this time with whitespace changes ignored:
$ diff -u --ignore-all-space orig-file file > patch
Now, apply the patch to orig-file and diff again, with whitespaces enabled - and you have the 2nd patch with only whitespace changes.
Git
With git, it's a bit easier:
$ git diff -w > patch
Related
I am versioning Microsoft Access VBA code, which is in general case insensitive. However changes the case of variable names happen every now in then (by the Access compiler or by the developer). This often leads to huge change set in my git workspace.
How can I revert or ignore changes, that only concern upper- or lowercase of file contents?
An example:
git init
echo "public sub example()\nend sub" > mdlExample.ACM
# ^-- lower e
git add --all
git commit --all --message "Initial Commit"
echo "public sub Example()\nend sub" > mdlExample.ACM
# ^-- upper E
I would love something like:
git restore --only-case-changes # not working
And then:
git status
> On branch master
> nothing to commit, working tree clean
Consider changing example="example" to Example="Example". How do you propose Git could decide which case change to ignore here? Now consider code snippets in comments, or stored as strings for code generators. I get wanting Git to make an annoying chore go away, but I think if you try to imagine telling Git exactly what you want you'll understand the context of your question a little better.
How can I revert or ignore changes, that only concern upper- or lowercase of file contents
When you want to temporarily ignore changes, when you want to do a diff or a blame without seeing those changes, you can use a "textconv" filter that normalizes the text you diff. I use those to do things like strip embedded timestamps out of generated html when diffing, quickest to hand atm is
[diff "doc-html"]
textconv = "sed 's,<span class=\"version\">Factorio [0-9.]*</span>,,;s,<[^/>][^>]*>,\\n&,g'"
wordRegex = "<[^>]*\\>|[^< \\t\\n]*"
in .git/config, and
doc-html/*.html diff=doc-html
*.cfg -diff
in .git/info/attributes.
so my what-changed diffs don't show me things I don't care about.
If you want to see the results of a diff ignoring case, try
[diff "nocase"]
textconv="tr A-Z a-z"
and drop * diff=nocase (or maybe*.vba diff=nocase) into .git/info/attributes. When you're done, take it out.
but for merging, my leadoff example should convince you that Git automatically and silently making case changes in repo content, even just in the text that looks like identifiers, is a Bad Idea. When there's a conflict, not just a one-sided change but two different changes, it's still going to take some human judgement to decide what the result should be. Fortunately, with any decent merge tool, resolving simple conflicts is down around subsecond range each.
You don't have to git restore anything: You could setup a clean content filter driver as illustrated here, which will automatically convert those cases on git diff/git commit.
That means:
you won't even see there is a diff
you won't add /commit anything because of that content filter driver.
Image from "Keyword Expansion" section of the "ProGit book"
This is done through:
a .gitattributes filter declaration, which means you can associate it only to certain files (through, for instance, their extension)
*.ACM filter=ignoreCase
a local git config filter.<driver>.clean to declare the actual script (which should be in your PATH)
git config filter.ignoreCase.clean ignoreCase.sh
# that give a .git/config file with:
[filter "ignoreCase"]
clean = ignoreCase.sh
The trick is:
Can you write a script which takes the content of an ACM file as input and produces the same ACM file as output, but with its strings converted?
You can have the filename in those scripts so you can do a diff and detect if said difference has to be adjusted, but you still need to write the right command to replace only "xxx" strings when their case changes in ACM files.
Note: jthill suggests in the comments to set the merge.renormalize config settings to tell Git that canonical representation of files in the repository has changed over time.
Have you considered the answer from this StackOverflow question:
How to perform case insensitive diff in Git
Maybe you can write a script to go and do the diff comparison for each commit and then add those commits to your branch. It may not be as simple as you like but maybe it will simplify the display of the changes to allow you to get to the case insensitive changes quicker?
cat <<-EOF
#lots of text
EOF
This syntax sure makes it simpler to manage lots of lines and also is just a single call to cat rather than a bunch of echos.
But is it safe to use <<-?
There are many text editor settings that may mess with spaces and tabs and its annoying to keep track of those. (portability is a concern)
Using only << would make the source code look dull without indentation.
Is there any safer and clean way to do this?
I have made a small edit and now it doesn't seem to be opinion based in any way.
You should realize that some users set their editors to automatically convert tabs into spaces. So when you work with multiple users on the same script, it is paramount to set up some base rules for this, which is annoying as you will end up with a one-day tab-vs-spaces war. Furthermore, I often consider tabs evil. They are good as a field separator, but they are awful when visualization depends on it. Everything depends on where the tabstops are defined and this can change from editor to editor and terminal to terminal. Sometimes. the tabstops are defined as a multiple of 8, sometimes as a multiple of 4. There is even the Posix command tabs which allows you to set the tabstops in any way you want
$ tabs 1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67
So ... tabs are evil!
My suggestion to you is to use the following:
printf "%s\n" 'fantastic line1' \
'awesome line2' \
'amazing line3' \
'unrivaled line4'
With gettext, the original (usually English) text of messages serves as
the message key ("msgid") for the translations. This means that every time the
original text changes, the msgid must be updated in all the .po files.
For real changes of the text, this is obviously unavoidable, as the
translator must update the translation.
However, if the change of the original does not change its meaning,
re-translation is superflous (e.g. change in punctation, whitespace
changes, or correction of a spelling mistake).
Is there a way to update the .po files automatically in that case?
I tried to use xgettext & msgmerge (with fuzzy matching turned on), but
fuzzy matching sometimes fails, plus this produces lots of ugly
"#,fuzzy" flags.
Note: There is a similar question:
How to efficiently work with gettext PO files when making small edits to large text values
However, it's about large strings, thus about a more specific problem.
One way to avoid the problem is to leave the msgids alone, have a .po file for the original language and make the fix inside that.
It always strikes me as being more of a work around than a proper fix though. For the next iteration (where there will definitely be more msgid changes) the msgid is changed and either the translators translate it in their usual update or each language is updated by hand when the msgid is changed.
I've had exactly this issue when doing minor changes to a django project. What I do is the following:
Change message in code.
Run find and replace on all translation files ("django.po"), replacing the old message (msgid) with the new one.
Run django-admin makemessages.
If I have done things right, the last step is superflous (i.e, you have done the change for gettext). django uses the gettext utilities, so it shouldn't matter how you make your message files.
I find and replace like so:
find . -name "*.po" -print | xargs sed -i 's/oldmessageid/newmessageid/g' Courtesy of http://rushi.vishavadia.com/blog/find-replace-across-multiple-files-in-linux
target: dependencies
command1
command2
On my system (Mac OS X), make seems to require that that Makefiles have a tab character preceding the the content of each command line, or it throws a syntax error.
This is an annoyance when creating or editing Makefiles because I have my editor set up to be all-spaces-all-the-time.
Can you make valid Makefiles without tab characters?
This is a syntax oddity/requirement of make, it has nothing to do with Mac OS X. Unfortunately, there's nothing you can do about it if you are going to use make.
Edit: GNU Make now supports a custom recipe prefix. See this answer.
You are not the first one to dislike this aspect of make. To quote Unix Haters' Handbook:
The problem with Dennis’s Makefile is that when he added the comment line, he inadvertently inserted a space before the tab character at the beginning of line 2. The tab character is a very important part of the syntax of Makefiles. All command lines (the lines beginning with cc in our example) must start with tabs. After he made his change, line 2 didn’t, hence the error.
“So what?” you ask, “What’s wrong with that?”
There is nothing wrong with it, by itself. It’s just that when you consider how other programming tools work in Unix, using tabs as part of the syntax is like one of those pungee stick traps in The Green Berets: the poor kid from Kansas is walking point in front of John Wayne and doesn’t see the trip wire. After all, there are no trip wires to watch out for in Kansas corn fields. WHAM!
In the time since this question was originally asked, a version of GNU Make has been released that allows you to use something other than Tab as the prefix character. From the mailing list announcement:
New special variable: .RECIPEPREFIX allows you to reset the recipe
introduction character from the default (TAB) to something else. The
first character of this variable value is the new recipe introduction
character. If the variable is set to the empty string, TAB is used again.
It can be set and reset at will; recipes will use the value active when
they were first parsed. To detect this feature check the value of $(.RECIPEPREFIX).
This feature was added in GNU Make 3.82, released in July 2010 (six months after this question's original ask date). Since it has in turn been three years and change since that, it's likely that other Make flavors have followed GNU Make.
There is a convoluted way of have a valid makefile without tabs.
If you change your makefile to read:
target: dependencies; command1; command2
If will work. If you want it on more than one line, then you can do:
target: dependencies; \
command1; \
command2
Messy, but it works.
If you have a vimrc in your profile you can add this line to prevent vim from changing to spaces:
autocmd FileType make setlocal noexpandtab
I too was struggling with this, and this fixed it for me. Spread the good word!
This does it for me if you would like to use spaces
.RECIPEPREFIX +=
Example
If you are using EditorConfig, you can add the following lines to your .editorconfig file to force your IDE to use tab for indentation instead of spaces in Makefile:
[Makefile]
indent_style = tab
In vim's insert mode, one can use Ctrl-v <TAB> to insert a literal tab, even if you have set the tab key to insert spaces. This doesn't answer your question, of course, but might be an alternative to the methods available to avoid needing literal tabs.
Until GNU Make 4.2
Steven Penny's answer works.
.RECIPEPREFIX +=
The reason why this works is described in my comment.
Since GNU Make 4.3 (released on 19 Jan 2020)
Behavior of += operator has been changed in a backward-incompatible way. If the left operand has an empty value, a space is no longer added.
You can instead use
.RECIPEPREFIX := $(.RECIPEPREFIX)<space>
, where <space> is a single space. Although $(.RECIPEPREFIX) is expanded as an empty value, this is needed not to let GNU Make ignore <space>. Note this code works even on GNU Make older than version 4.3.
in ubuntu: vi Makefiles
replace space by tab (or anything else you want):
:%s/<space chars>/^I/g
For ex replace 8 spaces by tab:
:%s/ /^I/g
Be attention: ^I insert with tab key, not ^ and I characters :D
Not portably. Certain flavours of make absolutely require tab characters. Yet another reason for preferring tabs over spaces :-)
I recently started using vim 7 (previously vim 6) and the smartindent setting. For the most part, it works well, though I'm so used to typing a tab after an open brace that it is almost counter-productive.
However, there is one piece of maniacal behaviour. When editing a shell script, I try to create a comment at the current indent level, but smartindent will have nothing to do with it. It insists that the comment must be at level 0 (no indent). What's worse, it breaks shift-right ('>>' and friends) so that they do not work. This is outright insubordination, and I'd like to know what's the best way to fix it?
(I'm also not keen on smartindent's ideas about indenting then after if.)
Preferred solutions will save me manual bashing - I'm being lazy. One option would be 'turn off smartindent when editing shell scripts (leave it on for the rest)'. Another option would be guidelines on how to find the control script for smartindent and what to edit to change the characteristics I don't like. The final option (which I don't need advice on how to do - just the hint that it is the best, or only, way to restore sanity) is to leave smartindent unset.
I saw the vaguely related question on "(PHP and) annoying vim unindent rules"; it doesn't provide me with the direct answer, though maybe the cindent and related items mentioned in there are in fact part of the answer.
Find the indent file, (e.g. /usr/share/vim/vim71/indent/sh.vim on my system)
This line looks like the problem:
setlocal indentkeys-=:,0#
Perhaps you can fix this in your .vimrc or load a custom indent file manually.
edit: It looks more complicated than I thought, but maybe there is something specifically set in the indenting file that you would need to fix.
2nd edit: Looks like I was completely wrong, Check out:
Restoring indent after typing hash
or
howto-configure-vim-to-not-put-comments-at-the-beginning-of-lines-while-editing
Well, after exploring some options, including using ':set cindent' instead of ':set smartindent', I've ended up reverting to just using ':set autoindent'. There probably are ways to make this stuff work exactly as I want it to, but it is messy enough and fiddly enough that I can't be bothered. I've worked fine with autoindent for the previous 20-odd years, and the benefits from the extra bells and whistles provided by smartindent are outweighed by the what I regard as its misbehaviour.
Thank you, Juan, for your assistance. Believe it or not, it did help - quite a lot.
I also discovered a couple of other neat commands, though, while following up on this:
>i}
>a}
These right-shift the block of code you are in. The 'i' version indents the body and not the closing braces (my preferred style), and the 'a' version indents the closing braces to (the version that is required at work).
Also, you can apply qualifiers to '%' in commands executed at the shell:
:make %:r.o
This would run make on the 'root' of the current file name (that's '%:r') followed by '.o'. Or, in other words, if I'm editing somefile.c, this executes make somefile.o.
Add the line below in your .vimrc
filetype indent on
(it will set the right indent mode depending on the filetype)
I had this same issue for a long time, until I realized that autoindent and smartindent are both unnecessary if "filetype indent on" is set in your vimrc - 'filetype indent on' uses the indent/sh.vim (or whatever language) file in your vim directory to figure out the indentation rules, and autoindent and smartindent both can interfere with it.
I haven't tested this with sh, but perl suddenly started behaving properly when I switched.
Sidenote: Juan's redirect, "Restoring indent after typing hash", is not a good solution - while it does correct the problem in one situation (typing code in), it doesn't change how the editor thinks it should be indented, so a re-indent (visual =, or normal ==) will shove it back to the left.
The previous answer suggesting:
:inoremap # X^H#
is excellent. It is the answer suggested by the VIM documentation at ":help smartindent". Note that ^H is entered using CTRL-V CTRL-H. The relevant section from the documentation is below.
When typing '#' as the first character in a new line, the indent for
that line is removed, the '#' is put in the first column. The indent
is restored for the next line. If you don't want this, use this
mapping: ":inoremap # X^H#", where ^H is entered with CTRL-V CTRL-H.
When using the ">>" command, lines starting with '#' are not shifted
right.
I have the following lines in my .vimrc and I don't observe the problem.
set smartindent
inoremap # X^H#
I used to have set autoindent after these two lines but it seems that it has no effect.
Yes that is very annoying. smartindent is really only for C like languages.
See how I enable the appropriate indenting based on language at:
http://www.pixelbeat.org/settings/.vimrc