home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / vim-2.0.lha / Vim-2.0 / src / mark.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  9.5 KB  |  474 lines

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