home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / v / vim_src.zip / MARK.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  8KB  |  411 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMitation
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * mark.c: functions for setting marks and jumping to them
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "mark.h"
  19.  
  20. /*
  21.  * This file contains routines to maintain and manipulate marks.
  22.  */
  23.  
  24. #define NMARKS            26            /* max. # of named marks */
  25. #define JUMPLISTSIZE    50            /* max. # of marks in jump list */
  26.  
  27. static struct mark pcmark;                    /* previous context mark */
  28. static struct mark namedm[NMARKS];            /* original vi marks */
  29. static struct filemark namedfm[NMARKS];        /* new marks with file nr */
  30. static struct filemark jumplist[JUMPLISTSIZE];    /* list of old pcmarks */
  31.  
  32. static int jumplistlen = 0;
  33. static int jumplistidx = 0;
  34.  
  35. static FPOS *mark2pos __ARGS((struct mark *));
  36.  
  37. /*
  38.  * setmark(c) - set named mark 'c' at current cursor position
  39.  *
  40.  * Returns TRUE on success, FALSE if no room for mark or bad name given.
  41.  */
  42.     int
  43. setmark(c)
  44.     int            c;
  45. {
  46.     int             i;
  47.  
  48.     if (islower(c))
  49.     {
  50.         i = c - 'a';
  51.         namedm[i].ptr = nr2ptr(Curpos.lnum);
  52.         namedm[i].col = Curpos.col;
  53.         return TRUE;
  54.     }
  55.     if (isupper(c))
  56.     {
  57.         i = c - 'A';
  58.         namedfm[i].mark.ptr = nr2ptr(Curpos.lnum);
  59.         namedfm[i].mark.col = Curpos.col;
  60.         namedfm[i].lnum = Curpos.lnum;
  61.         namedfm[i].fnum = 0;
  62.         return TRUE;
  63.     }
  64.     return FALSE;
  65. }
  66.  
  67. /*
  68.  * setpcmark() - set the previous context mark to the current position
  69.  *                 and insert it into the jump list
  70.  */
  71.     void
  72. setpcmark()
  73. {
  74.     int i;
  75. #ifdef ROTATE
  76.     struct filemark tempmark;
  77. #endif
  78.  
  79.     pcmark.ptr = nr2ptr(Curpos.lnum);
  80.     pcmark.col = Curpos.col;
  81.  
  82. #ifndef ROTATE
  83.     /*
  84.      * simply add the new entry at the end of the list
  85.      */
  86.     jumplistidx = jumplistlen;
  87. #else
  88.     /*
  89.      * If last used entry is not at the top, put it at the top by rotating
  90.      * the stack until it is (the newer entries will be at the bottom).
  91.      * Keep one entry (the last used one) at the top.
  92.      */
  93.     if (jumplistidx < jumplistlen)
  94.         ++jumplistidx;
  95.     while (jumplistidx < jumplistlen)
  96.     {
  97.         tempmark = jumplist[jumplistlen - 1];
  98.         for (i = jumplistlen - 1; i > 0; --i)
  99.             jumplist[i] = jumplist[i - 1];
  100.         jumplist[0] = tempmark;
  101.         ++jumplistidx;
  102.     }
  103. #endif
  104.  
  105.         /* only add new entry if it differs from the last one */
  106.     if (jumplistlen == 0 || jumplist[jumplistidx - 1].mark.ptr != pcmark.ptr)
  107.     {
  108.             /* if jumplist is full: remove oldest entry */
  109.         if (++jumplistlen > JUMPLISTSIZE)
  110.         {
  111.             jumplistlen = JUMPLISTSIZE;
  112.             for (i = 1; i < jumplistlen; ++i)
  113.                 jumplist[i - 1] = jumplist[i];
  114.             --jumplistidx;
  115.         }
  116.  
  117.         jumplist[jumplistidx].mark = pcmark;
  118.         jumplist[jumplistidx].lnum = Curpos.lnum;
  119.         jumplist[jumplistidx].fnum = 0;
  120.         ++jumplistidx;
  121.     }
  122. }
  123.  
  124. /*
  125.  * move "count" positions in the jump list (count may be negative)
  126.  */
  127.     FPOS *
  128. movemark(count)
  129.     int count;
  130. {
  131.     FPOS        *pos;
  132.  
  133.     if (jumplistlen == 0)            /* nothing to jump to */
  134.         return (FPOS *)NULL;
  135.  
  136.     if (jumplistidx + count < 0 || jumplistidx + count >= jumplistlen)
  137.         return (FPOS *)NULL;
  138.  
  139.     /*
  140.      * if first CTRL-O or CTRL-I command after a jump, add cursor position to list
  141.      */
  142.     if (jumplistidx == jumplistlen)
  143.     {
  144.         setpcmark();
  145.         --jumplistidx;        /* skip the new entry */
  146.     }
  147.  
  148.     jumplistidx += count;
  149.     if (jumplist[jumplistidx].mark.ptr == NULL)    /* jump to other file */
  150.     {
  151.         if (getaltfile(jumplist[jumplistidx].fnum - 1, jumplist[jumplistidx].lnum, FALSE))
  152.             return (FPOS *)NULL;
  153.         Curpos.col = jumplist[jumplistidx].mark.col;
  154.         jumplist[jumplistidx].fnum = 0;
  155.         jumplist[jumplistidx].mark.ptr = nr2ptr(Curpos.lnum);
  156.         pos = (FPOS *)-1;
  157.     }
  158.     else
  159.         pos = mark2pos(&jumplist[jumplistidx].mark);
  160.     return pos;
  161. }
  162.  
  163. /*
  164.  * getmark(c) - find mark for char 'c'
  165.  *
  166.  * Return pointer to FPOS if found
  167.  *        NULL if no such mark.
  168.  *        -1 if mark is in other file (only if changefile is TRUE)
  169.  */
  170.     FPOS *
  171. getmark(c, changefile)
  172.     int            c;
  173.     int            changefile;
  174. {
  175.     FPOS    *posp;
  176.  
  177.     posp = NULL;
  178.     if (c == '\'' || c == '`')            /* previous context mark */
  179.         posp = mark2pos(&pcmark);
  180.     else if (islower(c))                /* normal named mark */
  181.         posp = mark2pos(&(namedm[c - 'a']));
  182.     else if (isupper(c))                /* named file mark */
  183.     {
  184.         c -= 'A';
  185.         posp = mark2pos(&(namedfm[c].mark));
  186.         if (posp == NULL && namedfm[c].lnum != 0 && (changefile || samealtfile(namedfm[c].fnum - 1)))
  187.         {
  188.             if (!getaltfile(namedfm[c].fnum - 1, namedfm[c].lnum, TRUE))
  189.             {
  190.                 Curpos.col = namedfm[c].mark.col;
  191.                 namedfm[c].fnum = 0;
  192.                 namedfm[c].mark.ptr = nr2ptr(Curpos.lnum);
  193.                 posp = (FPOS *)-1;
  194.             }
  195.         }
  196.     }
  197.     return posp;
  198. }
  199.  
  200.     static FPOS *
  201. mark2pos(markp)
  202.     struct mark *markp;
  203. {
  204.     static FPOS pos;
  205.  
  206.     if (markp->ptr != NULL && (pos.lnum = ptr2nr(markp->ptr, (linenr_t)1)) != 0)
  207.     {
  208.         pos.col = markp->col;
  209.         return (&pos);
  210.     }
  211.     return (FPOS *)NULL;
  212. }
  213.  
  214. /*
  215.  * clrallmarks() - clear all marks
  216.  *
  217.  * Used mainly when trashing the entire buffer during ":e" type commands
  218.  */
  219.     void
  220. clrallmarks()
  221. {
  222.     static int             i = -1;
  223.  
  224.     if (i == -1)        /* first call ever: initialize */
  225.         for (i = 0; i < NMARKS; i++)
  226.             namedfm[i].lnum = 0;
  227.  
  228.     for (i = 0; i < NMARKS; i++)
  229.     {
  230.         namedm[i].ptr = NULL;
  231.         namedfm[i].mark.ptr = NULL;
  232.     }
  233.     pcmark.ptr = NULL;
  234.     qf_clrallmarks();
  235.     for (i = 0; i < jumplistlen; ++i)
  236.         jumplist[i].mark.ptr = NULL;
  237. }
  238.  
  239. /*
  240.  * increment the file number for all filemarks
  241.  * called when adding a file to the file stack
  242.  */
  243.     void
  244. incrmarks()
  245. {
  246.     int            i;
  247.  
  248.     for (i = 0; i < NMARKS; i++)
  249.         ++namedfm[i].fnum;
  250.  
  251.     for (i = 0; i < jumplistlen; ++i)
  252.     {
  253. #if 0        /* this would take too much time */
  254.         if (jumplist[i].fnum == 0)    /* current file */
  255.             jumplist[i].lnum = ptr2nr(jumplist[i].mark.ptr, 1);
  256. #endif
  257.         ++jumplist[i].fnum;
  258.     }
  259. }
  260.  
  261. /*
  262.  * decrement the file number for the filemarks of the current file
  263.  * called when not adding the current file name to the file stack
  264.  */
  265.     void
  266. decrmarks()
  267. {
  268.     int            i;
  269.  
  270.     for (i = 0; i < NMARKS; i++)
  271.         if (namedfm[i].fnum == 1)
  272.             namedfm[i].fnum = 0;
  273.  
  274.     for (i = 0; i < jumplistlen; ++i)
  275.         if (jumplist[i].fnum == 1)
  276.             jumplist[i].fnum = 0;
  277. }
  278.  
  279. /*
  280.  * adjustmark: set new ptr for a mark
  281.  * if new == NULL the mark is effectively deleted
  282.  */
  283.    void
  284. adjustmark(old, new)
  285.         char *old, *new;
  286. {
  287.         register int i;
  288.  
  289.         for (i = 0; i < NMARKS; ++i)
  290.         {
  291.             if (namedm[i].ptr == old)
  292.                 namedm[i].ptr = new;
  293.             if (namedfm[i].mark.ptr == old)
  294.             {
  295.                 namedfm[i].mark.ptr = new;
  296.                 if (new == NULL)
  297.                     namedfm[i].lnum = 0;        /* delete this mark */
  298.             }
  299.         }
  300.         if (pcmark.ptr == old)
  301.                 pcmark.ptr = new;
  302.         for (i = 0; i < jumplistlen; ++i)
  303.                 if (jumplist[i].mark.ptr == old)
  304.                         jumplist[i].mark.ptr = new;
  305.         qf_adjustmark(old, new);
  306. }
  307.  
  308. /*
  309.  * get name of file from a filemark (use the occasion to update the lnum)
  310.  */
  311.     char *
  312. fm_getname(fmark)
  313.     struct filemark *fmark;
  314. {
  315.     linenr_t    nr;
  316.     char        *name;
  317.  
  318.     if (fmark->fnum != 0)                        /* maybe not current file */
  319.     {
  320.         name = getaltfname(fmark->fnum - 1);
  321.         if (fnamecmp(name, Filename) != 0)        /* not current file */
  322.             return name;
  323.         fmark->fnum = 0;
  324.     }
  325.     if (fmark->mark.ptr == NULL)
  326.         fmark->mark.ptr = nr2ptr(fmark->lnum);    /* update ptr */
  327.     else
  328.     {
  329.         nr = ptr2nr(fmark->mark.ptr, (linenr_t)1);
  330.         if (nr != 0)
  331.             fmark->lnum = nr;                    /* update lnum */
  332.     }
  333.     return "current";
  334. }
  335.  
  336. /*
  337.  * print the marks (use the occasion to update the line numbers)
  338.  */
  339.     void
  340. domarks()
  341. {
  342.     int            i;
  343.     char        *name;
  344.  
  345.     settmode(0);
  346.     outstrn("\nmark line  file\n");
  347.     for (i = 0; i < NMARKS; ++i)
  348.     {
  349.         if (namedm[i].ptr != NULL)
  350.         {
  351.             sprintf(IObuff, " %c %5ld\n",
  352.                 i + 'a',
  353.                 ptr2nr(namedm[i].ptr, (linenr_t)1));
  354.             outstrn(IObuff);
  355.         }
  356.         flushbuf();
  357.     }
  358.     for (i = 0; i < NMARKS; ++i)
  359.     {
  360.         if (namedfm[i].lnum != 0)
  361.         {
  362.             name = fm_getname(&namedfm[i]);
  363.             if (name == NULL)        /* file name not available */
  364.                 continue;
  365.  
  366.             sprintf(IObuff, " %c %5ld  %s\n",
  367.                 i + 'A',
  368.                 namedfm[i].lnum,
  369.                 name);
  370.             outstrn(IObuff);
  371.         }
  372.         flushbuf();
  373.     }
  374.     settmode(1);
  375.     wait_return(TRUE);
  376. }
  377.  
  378. /*
  379.  * print the jumplist (use the occasion to update the line numbers)
  380.  */
  381.     void
  382. dojumps()
  383. {
  384.     int            i;
  385.     char        *name;
  386.  
  387.     settmode(0);
  388.     outstrn("\n jump line  file\n");
  389.     for (i = 0; i < jumplistlen; ++i)
  390.     {
  391.         if (jumplist[i].lnum != 0)
  392.         {
  393.             name = fm_getname(&jumplist[i]);
  394.             if (name == NULL)        /* file name not available */
  395.                 continue;
  396.  
  397.             sprintf(IObuff, "%c %2d %5ld  %s\n",
  398.                 i == jumplistidx ? '>' : ' ',
  399.                 i + 1,
  400.                 jumplist[i].lnum,
  401.                 name);
  402.             outstrn(IObuff);
  403.         }
  404.         flushbuf();
  405.     }
  406.     if (jumplistidx == jumplistlen)
  407.         outstrn(">\n");
  408.     settmode(1);
  409.     wait_return(TRUE);
  410. }
  411.