Vim Tips Wiki
Vim Tips Wiki
Advertisement

Duplicate tip

This tip is very similar to the following:

These tips need to be merged – see the merge guidelines.

Tip 482 Printable Monobook Previous Next

created 2003 · complexity intermediate · author hypertext organizer · version 5.7


No one has a perfect memory. You can make small text files with items you want to remember, and grep them later to search for what you need.

Or, you can keep a single file, and use Vim to organize it, in the same way that Vim organizes its Help. Here is an extract from my own Memo:

*memo.txt* My Memo - extending my poor memory |guide|
----------------------------------------------------------------
*subjects* *toc*
|cmd| command tips |def| definitions
|dev| developments |ed| editors |friends| friends
|lang| languages |misc| others
|private| personal info |sys| system
----------------------------------------------------------------
Commands *cmd*
*General
http://www.cslab.vt.edu/manuals
 ...
|doskey| DOS key utility
 <F8>: expand history
|man| Unix manual
 man foo
 nroff -man foo.1 | less
 nroff -man foo.1 | a2ps -m
|unix|
http://gd.tuwien.ac.at/linuxcommand.org/
|winhelp|
 ...
----------------------------------------------------------------
Development *develop* *dev*
 ...
----------------------------------------------------------------
vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:

Some explanations:

The last line instructs Vim with a number of editing settings. The most important one here is "ft=help", which says file-type is "help". So Vim will highlight things for us.

You can use *foo* to indicate an anchor to the "help" system of Vim. If you press Ctrl+] on a word "foo", the cursor will jump to the first *foo*. You can also see |foo| as a way to highlight it as implicit keywords.

This is not magic. The mechanism behind it is the tag system. Vim needs to have the following tag file to go to where you want it to go:

%userprofile% memo.txt /*%userprofile%*
.htaccess meo.txt /*.htaccess*
access memo.txt /*access*
access.conf memo.txt /*access.conf*
addressbook memo.txt /*addressbook*
anchor_keyword memo.txt /*anchor_keyword*
apache memo.txt /*apache*
as index.txt /*as*
at index.txt /*at*
awk index.txt /*awk*

Each line defines a tag, the first element is the keyword, the second is the file where the tag belongs (yes, you can use multiple files as long as you know what they are), and the last element is the command which Vim has to perform at the keyword.

How to write these tags? You can find this utility to do it:

cc doctags.c -o doctags
doctags memo.txt | sort -f | awk -f cases.awk >tags
uniq -d -2 tags
/* doctags.c (see Vim source!) */
/* vim:set ts=4 sw=4:
 * this program makes a tags file for vim_ref.txt
 *
 * Usage: doctags vim_ref.txt vim_win.txt ... >tags
 *
 * A tag in this context is an identifier between stars, e.g. *c_files*
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define LINELEN 200

 int
main(argc, argv)
 int argc;
 char **argv;
{
 char line[LINELEN];
 char *p1, *p2;
 char *p;
 FILE *fd;

 if (argc <= 1)
 {
  fprintf(stderr, "Usage: doctags docfile ... >tags\n");
  exit(1);
 }
 printf("help-tags\ttags\t1\n");
 while (--argc > 0)
 {
  ++argv;
  fd = fopen(argv[0], "r");
  if (fd == NULL)
  {
   fprintf(stderr, "Unable to open %s for reading\n", argv[0]);
   continue;
  }
  while (fgets(line, LINELEN, fd) != NULL)
  {
   p1 = strchr(line, '*'); /* find first '*' */
   while (p1 != NULL)
   {
    p2 = strchr(p1 + 1, '*'); /* find second '*' */
    if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */
    {
     for (p = p1 + 1; p < p2; ++p)
      if (*p == ' ' || *p == '\t' || *p == '|')
       break;
     /*
      * Only accept a *tag* when it consists of valid
      * characters and is followed by a white character or
      * end-of-line.
      */
     if (p == p2 && (p1 == line || p1[-1] != '-') &&
     (strchr(" \t\n\r", p[1]) != NULL || p[1] == '\0'))
     {
      *p2 = '\0';
      ++p1;
      printf("%s\t%s\t/*", p1, argv[0]);
      while (*p1)
      {
       /* insert backslash before '\' and '/' */
       if (*p1 == '\' || *p1 == '/')
        putchar('\');
       putchar(*p1);
       ++p1;
      }
      printf("*\n");
      p2 = strchr(p2 + 1, '*'); /* find next '*' */
     }
    }
    p1 = p2;
   }
  }
  fclose(fd);
 }
 return 0;
}
/* cases.awk */
{
print tolower($1) "\t" $2 "\t" tolower($3);
}

Comments[]

This is all as clear as mud. It would be great if someone could come up with a straightforward explaination of how to write and use a memo file. Or replace this lot with a linkto something more useful.


TODO Omit the misguided suggestions above for using doctags, and below for using tags.py, and use Vim's :helptags as in the next comment.


See :help :helptags.

Make your own tags file within Vim with:

:execute "helptags " . expand("%:p:h")

from within the open file.


There is one downside with :helptags. It operates only on *.txt files.

Here is another method for generating a tags file for *word* style tags; written in python and based off the ptags.py from the python22 distribution.

Usage: tags.py [file] [file,etc]

Example: tags.py myfile.html myfile.c etc

#! /usr/bin/env python
# tags.py
#{{{ File header information
"""
/*!
\file tags.py
\brief Create a tags file (of *WORDS*), usable with VIM61, possibly earlier.
\note based on ptags.py from the python22 distribution
 modifed by Feral to find only *word* style tags (for my documtation) output tailored for VIM6.1
\author Original author unknown, based on ptags.py from the python22 distribution.
 This file modified and maintained by Feral
\version 1.02
\note $Id$

Changelog:
 1.01: [Feral:240/02@08:36] now warns on a duplicate entry, slow and crude method (checks each addition to tags)
 1.00: [yesterday]
 Initial version, based on ptags.py from the python22 distrobution.
*/
"""
#}}}

import sys, re, os

tags = [] # modified global variable

def main():
  args = sys.argv[1:]
  print args
  for file in args:
  treat_file(file)
  # keep in mind that the tags are sorted, this line !should! end up at the top...
  tags.append("!_TAG_FILE_SORTED\t1\n")
  if tags:
    fp = open('tags', 'w')
    tags.sort()
    for s in tags:
      fp.write(s)

matcher = re.compile(r'\*\w+\*')

def treat_file(file):
  print "treating file", file
  dacount = 0
  try:
    fp = open(file, 'r')
  except:
    print >> sys.stderr, 'Cannot open %s' % file
    return
  base = os.path.basename(file)
  while True:
    line = fp.readline()
    if not line:
    break
    m = matcher.search(line)
    if m:
      content = m.group()
      s = content + '\t' + base + '\t/' + content + '\n'
      for item in tags:
        if item == s:
          print "Duplicate entry:", content
      tags.append(s)
      dacount += 1
  print "\t", dacount, "matches."

if __name__ == '__main__':
  main()

Also see Thlnk.vim script#293.


It will be better if combined with the folding. I put this on the modeline:

vim:fdm=marker:tw=78:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:

And add folding marks at the end of the section title, like this:

==================================================
Commands {{{1
==================================================

"{{{1" is the default folding mark for level one. You can use multiple level folders as well (:he Folding). Vim will folder the items automatically so you can get all items at one glance. Really nice feature!


I just integrated much of these functions (links, folding, etc) into one script in script#828.


Advertisement