Vim Tips Wiki
Advertisement

Proposed tip Please edit this page to improve it, or add your comments below (do not use the discussion page).

Please use new tips to discuss whether this page should be a permanent tip, or whether it should be merged to an existing tip.
created October 9, 2007 · complexity advanced · author Fritzophrenic · version 7.0

Especially when editing source code, there is often a copyright notice embedded in the file. Insert one of the following in a vimrc file to automatically update this copyright notice in ALL FILES when writing them.

Simple Copyright Notices

" Automatically update copyright notice with current year
autocmd BufWritePre *
      \ if &modified |
          \   exe "g#\\cCOPYRIGHT \\(".strftime("%Y")."\\)\\@![0-9]\\{4\\}\\(-".strftime("%Y")."\\)\\@!#s#\\([0-9]\\{4\\}\\)\\(-[0-9]\\{4\\}\\)\\?#\\1-".strftime("%Y") |
      \ endif

This replaces yyyy or yyyy-yyyy with yyyy-<current year> on any line in the file containing an outdated "COPYRIGHT yyyy" notice (case-insensitive). It only does this if the file has been modified.

An explaination of the command string follows:

  • g# - search and replace only on a line matching copyright notice patten. '#' is used rather than the customary '/' to avoid confusion with all the '\' characters.
  • \\cCOPYRIGHT - match on text COPYRIGHT followed by a space (case-insensitive)
  • \\(".strftime("%Y")."\\)\\@! - only match when the entire match does not consist of the current year (i.e. don't update a notice containing only the current year, like "Copyright 2007").
  • [0-9]\\{4\\} - matches a 4-digit number for the first year in the notice
  • \\(-".strftime("%Y")."\\)\\@! - don't match on up-to-date notices
  • #s# - search and replace the outdated year
  • \\([0-9]\\{4\\}\\) - match a 4-digit year and give it a backreference
  • \\(-[0-9]\\{4\\}\\)\\? - optionally match an ending year, e.g. the "-2006" in "copyright 2000-2006".
  • #\\1-".strftime("%Y") - replace the found text with the first year in the copyright, a hyphen, and the current year

This script will "jump" to the copyright notice whenever it gets updated. If this is not desired, you can put in a command before the g#s# to create a mark and a command after it to jump back to the mark.

References

More Complex Notices

The above works great for simple copyrights with just a range of years, but if you need more precise/correct ones (that skip years something was not worked on, e.g. "copyright 2004, 2006-2008") it will fail miserably. Here's what to replace the guts with, instead of the g#s## command above:

          \   exe '%s:'.
          \       '\cCOPYRIGHT\s*\%((c)\|&copy;\|©\)\?\s*'.
          \         '\%([0-9]\{4}\(-[0-9]\{4\}\)\?,\s*\)*\zs'.
          \         '\('.
          \           '\%('.strftime("%Y").'\)\@![0-9]\{4\}'.
          \           '\%(-'.strftime("%Y").'\)\@!\%(-[0-9]\{4\}\)\?'.
          \         '\&'.
          \           '\%([0-9]\{4\}-\)\?'.
          \           '\%('.(strftime("%Y")-1).'\)\@!'.
          \           '\%([0-9]\)\{4\}'.
          \         '\)'.
          \         '\ze\%(\%([0-9]\{4\}\)\@!.\)*$:'.
          \       '&, '.strftime("%Y").':e' |
          \   exe '%s:'.
          \       '\cCOPYRIGHT\s*\%((c)\|&copy;\|©\)\?\s*'.
          \         '\%([0-9]\{4}\%(-[0-9]\{4\}\)\?,\s*\)*\zs'.
          \           '\%('.strftime("%Y").'\)\@!\([0-9]\{4\}\)'.
          \           '\%(-'.strftime("%Y").'\)\@!\%(-[0-9]\{4\}\)\?'.
          \         '\ze\%(\%([0-9]\{4\}\)\@!.\)*$:'.
          \       '\1-'.strftime("%Y").':e' |

This makes two passes, one to update years that it needs a comma for, the next to update years it can use a hyphen for.

First Pass (needs a comma)

Summary: Replace all lines with a copyright notice, that do NOT end in the previous or current year, with a comma and the current year.

  • %s: - start a "replace in all lines" search, using ':' rather than the customary '/' for clarity.
  • \cCOPYRIGHT\s*\%((c)\|&copy;\|©\)\?\s* - find lines containing the copyright flag (copyright {optional symbol}) as in the simple method.
  • \%({below}\)* - match any number of year ranges followed by commas, but DO NOT use them for backreferences.
  • [0-9]\{4}\(-[0-9]\{4\}\)\?,\s* - match a year or year range, followed by a comma and whitespace.
  • \zs - Place the "start of match" at this point. This means that any matched text previous to this point (i.e. the copyright flag, and any year-ranges followed by commas) will NOT be replaced with the replacement text.
  • \({below}\&{below}\) - The parentheses group two "concats" separated by the \&. All concats must match at the same place for the pattern to match. When it matches, it matches the final concat.
  • \%('.strftime("%Y").'\)\@![0-9]\{4\} - match any year that is not the current year.
  • \%(-'.strftime("%Y").'\)\@!\%(-[0-9]\{4\}\)\? - optionally match any year range ending ("-{year}") to complete the first concat
  • \%([0-9]\{4\}-\)\? - optionally match a year range beginning ("-{year}")
  • \%('.(strftime("%Y")-1).'\)\@!\%([0-9]\)\{4\} - match any year except for the previous year (note, current year already known NOT to match) to complete the final concat
  • \ze - place the end of the match at this point, so that any text following this point is NOT affected by the replacement.
  • \%(\%([0-9]\{4\}\)\@!.\)*$ - match any text that does not contain a year, until the end of the line. This ensures that we captured only the very last year in the line with our final concat, above.
  • :&, '.strftime("%Y") - replace with the entire match (i.e. the last concat above) followed by a comma and the current year. Recall that the match start and end were defined carefully so that only the desired text is replaced.
  • :e - suppress error when no match is found so you don't see error messages when your copyright is up-to-date, and to allow the mapping to continue on to the second pass...

Second Pass (can use a hyphen)

Summary: Replace all remaining lines with a copyright notice, that do NOT end in the current year (i.e. they end in the previous year), with a hyphen and the current year.

  • %s: - start a "replace in all lines" search, using ':' rather than the customary '/' for clarity.
  • \cCOPYRIGHT\s*\%((c)\|&copy;\|©\)\?\s* - find lines containing the copyright flag (copyright {optional symbol}) as in the simple method.
  • \%({below}\)* - match any number of year ranges followed by commas, but DO NOT use them for backreferences.
  • [0-9]\{4}\(-[0-9]\{4\}\)\?,\s* - match a year or year range, followed by a comma and whitespace.
  • \zs - Place the "start of match" at this point. This means that any matched text previous to this point (i.e. the copyright flag, and any year-ranges followed by commas) will NOT be replaced with the replacement text.
  • \%('.strftime("%Y").'\)\@!\([0-9]\{4\}\) - match any year except for the current year, and place it in the first backreference (note the use of \%(\) in every previous grouping)
  • \%(-'.strftime("%Y").'\)\@!\%(-[0-9]\{4\}\)\? - optionally match a year range ending that does NOT include the current year.
  • \ze - place the end of the match at this point, so that any text following this point is NOT affected by the replacement.
  • \%(\%([0-9]\{4\}\)\@!.\)*$ - match any text that does not contain a year, until the end of the line. This ensures that we captured only the very last year in the line.
  • \1-'.strftime("%Y") - replace with the first backreference (i.e. the first year in the final year range of the line), followed by a hyphen and the current year.
  • :e - suppress error when no match is found so you don't see error messages whenever your copyright notice is up-to-date.

References

Comments


Advertisement