Fossil

Changes On Branch diff-keyboard-navigation
Login

Changes On Branch diff-keyboard-navigation

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch diff-keyboard-navigation Excluding Merge-Ins

This is equivalent to a diff from 92372ce946 to 361fc76769

2024-12-17
12:38
Send the --from argument of the "fossil ui" command encoded as hexadecimal, to work around quoting problems on Windows. [forum:/forumpost/cfc22d41b19a1a96|Forum post cfc22d41b19a1a96]. ... (check-in: 593ceca27d user: drh tags: trunk)
06:56
Sync with trunk. ... (Leaf check-in: 5fbb14f73a user: florian tags: diff-word-wrap)
06:36
Sync with trunk. ... (Leaf check-in: 361fc76769 user: florian tags: diff-keyboard-navigation)
06:32
Consistent naming of the "Hide Diff" links to skip server-side diff generation. Note the naming conflict with the scripted link to show and hide the generated diffs. ... (check-in: aa7ddd8094 user: florian tags: diff-keyboard-navigation)
06:26
Sync with trunk. ... (Leaf check-in: 215fc593d0 user: florian tags: timeline-keyboard-navigation)
06:12
On the new /ckout UI page, output the page footer only once. ... (check-in: 92372ce946 user: florian tags: trunk)
2024-12-16
16:22
Add missing word in the help text for 'merge'. ... (check-in: bdc6bb1cfb user: danield tags: trunk)

Changes to src/fossil.diff.js.

82
83
84
85
86
87
88






89
90




























































































































91
92
93
94
95
96
97
        /* Toggle all entries to match this new state. We use click()
           instead of ckbox.checked=... so that the on-change event handler
           fires. */
        if(ckbox.checked!==show) ckbox.click();
      }
    }, false);
  }






});





























































































































window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const Diff = F.diff = {
    e:{/*certain cached DOM elements*/},
    config: {
      chunkLoadLines: (
        F.config.diffContextLines * 3







>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
        /* Toggle all entries to match this new state. We use click()
           instead of ckbox.checked=... so that the on-change event handler
           fires. */
        if(ckbox.checked!==show) ckbox.click();
      }
    }, false);
  }
  function resetToggles(){
    var cb = document.querySelectorAll(
                        'input[type="checkbox"].diff-toggle:not(:checked)');
    for( var i=0; i<cb.length; i++ ) cb[i].checked = true;
  }
  setTimeout(resetToggles);
});

/*
** Diff keyboard navigation shortcuts:
**
** ### NOTE: The keyboard shortcuts are listed in the /vdiff help screen. ###
**
** Ideas and TODOs:
**
**  o The `timeline-keyboard-navigation' branch removes the unload handler from
**    pages containing timeline snippets, so it's no longer necessary to reset
**    the diff toggles on back/forward navigation in case the mentioned branch
**    is merged with `diff-keyboard-navigation'.
*/
(function(){
  window.addEventListener('load',function(){
    function btnScrollIntoView(e){
      e = e.parentElement;
      var rc = e.getBoundingClientRect();
      var y = 0;
      do{
        y += e.offsetTop;
      }while( e = e.offsetParent );
      window.scrollTo(0,y-6*rc.height);
    }
    document.addEventListener('keydown',function(evt){
      if( evt.target.tagName=='INPUT' || evt.target.tagName=='SELECT' ) return;
      var
        mSHIFT = 1<<13,
        kSHOW = mSHIFT | 73 /* SHIFT+I */,
        kHIDE = 73 /* I */,
        kNEXT = 80 /* P */,
        kPREV = 79 /* O (Letter O) */,
        kUNID = 85 /* U */,
        kSBSD = mSHIFT | 85 /* SHIFT+U */,
        kNULD = 48 /* 0 (Digit Zero) */,
        kUDCD = 68 /* D */,
        mod = evt.altKey<<15|evt.ctrlKey<<14|evt.shiftKey<<13|evt.metaKey<<12,
        key = ( evt.which || evt.keyCode ) | mod;
      switch( key ){
        case kSHOW:
        case kHIDE:
        case kNEXT:
        case kPREV:
        case kUNID:
        case kSBSD:
        case kNULD:
        case kUDCD: break;
        default: return;
      }
      evt.preventDefault();
      evt.stopPropagation();
      if( key==kSHOW || key==kHIDE ){
        var btn = document.getElementsByClassName('diff-toggle');
        if( btn.length>0 ){
          var chg = 0;
          for( var i=0; i<btn.length; i++ ){
            if( btn[i].checked && key==kHIDE ){
              btn[i].click();
              chg++;
            }
            else if( !btn[i].checked && key==kSHOW ){
              btn[i].click();
              chg++;
            }
          }
          if( chg>0 ) btnScrollIntoView(btn[0]);
        }
      }
      else if( key==kNEXT || key==kPREV ){
        var btn = document.getElementsByClassName('diff-toggle');
        if( btn.length>1 ){
          var nFolded = 0, n = -2;
          for( var i=0; i<btn.length; i++ ){
            if( !btn[i].checked ) nFolded++;
          }
          if( nFolded==0 ){
            n = ( key==kNEXT ? 0 : btn.length-1 );
            for( var i=0; i<btn.length; i++ ){
              if( n!=i ) btn[i].click();
            }
          }
          else{
            for( var i=0; i<btn.length; i++ ){
              if( btn[i].checked ){
                if( n==-2 ) n = ( key==kNEXT ? i+1 : i-1 );
                if( n!=i ) btn[i].click();
              }
            }
          }
          if( n==-2 ) n = ( key==kNEXT ? 0 : btn.length-1 );
          if( n in btn ){
            if( !btn[n].checked ) btn[n].click();
            btnScrollIntoView(btn[n]);
          }
        }
        else if( btn.length>0 ){
          btn[0].click();
          btnScrollIntoView(btn[0]);
        }
      }
      else if( key==kUNID || key==kSBSD || key==kNULD ){
        var T={}; T[kUNID]='unified', T[kSBSD]='side-by-side', T[kNULD]='hide';
        var
          type = T[key],
          link = document.querySelector('.smb-'+type+'-diff')
                  || document.querySelector('.sml-'+type+'-diff'),
          href;
        if( link ){
          if( link.dataset.href ) href = link.dataset.href;   // anti-bot
          else href = link.href;
        }
        if( href && href!=location.href.slice(-href.length) ){
          location.href = href;
        }
      }
      else if( key==kUDCD ){
        if( !/[?&]udc=1/.test(location.href) ){
          var sep = /\?/.test(location.href) ? '&' : '?';
          location.href += sep + 'udc=1';
        }
      }
    }/*,true*/);
  },false);
}());

window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const Diff = F.diff = {
    e:{/*certain cached DOM elements*/},
    config: {
      chunkLoadLines: (
        F.config.diffContextLines * 3

Changes to src/info.c.

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  }
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int diffType){
  if( diffType==0 ) return;
  builtin_fossil_js_bundle_or("diff", NULL);
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/







|







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  }
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int diffType){
  /* Load fossil.diff.js even if diffType==0 to enable keyboard shortcuts. */
  builtin_fossil_js_bundle_or("diff", NULL);
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
640
641
642
643
644
645
646





647


648
649
650


651
652
653
654
655
656
657
658
  if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
    DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
  }else{
    DCfg.diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
  }
  @ <div class="sectionmenu info-changes-menu">
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";





  if( diffType!=1 ){


    @ %z(chref("button","%R?diff=1%s",zW))Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){


    @ %z(chref("button","%R?diff=2%s",zW))Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R?diff=%d",diffType))\
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
      @ %z(chref("button","%R?diff=%d&w",diffType))Ignore&nbsp;Whitespace</a>







>
>
>
>
>

>
>
|


>
>
|







640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
    DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
  }else{
    DCfg.diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
  }
  @ <div class="sectionmenu info-changes-menu">
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    /* Class "smb-hide-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-hide-diff";
    @ %z(chref(zBtnClass,"%R?diff=0"))Hide&nbsp;Diff</a>
  }
  if( diffType!=1 ){
    /* Class "smb-unified-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-unified-diff";
    @ %z(chref(zBtnClass,"%R?diff=1%s",zW))Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){
    /* Class "smb-side-by-side-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-side-by-side-diff";
    @ %z(chref(zBtnClass,"%R?diff=2%s",zW))Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R?diff=%d",diffType))\
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
      @ %z(chref("button","%R?diff=%d&w",diffType))Ignore&nbsp;Whitespace</a>
820
821
822
823
824
825
826



827
828
829
830
831
832
833
** If the "exbase=PATH" query parameter is provided, then the diff shown
** uses the files in PATH as the baseline.  This is the same as using
** the "--from PATH" argument to the "fossil diff" command-line.  In fact,
** when using "fossil ui --from PATH", the --from argument becomes the value
** of the exbase query parameter for the start page.
**
** Other query parameters related to diffs are also accepted.



*/
void ckout_page(void){
  int vid;
  const char *zHome;          /* Home directory */
  int nHome;
  const char *zExBase;
  char *zHostname;







>
>
>







829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
** If the "exbase=PATH" query parameter is provided, then the diff shown
** uses the files in PATH as the baseline.  This is the same as using
** the "--from PATH" argument to the "fossil diff" command-line.  In fact,
** when using "fossil ui --from PATH", the --from argument becomes the value
** of the exbase query parameter for the start page.
**
** Other query parameters related to diffs are also accepted.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void ckout_page(void){
  int vid;
  const char *zHome;          /* Home directory */
  int nHome;
  const char *zExBase;
  char *zHostname;
885
886
887
888
889
890
891



892
893
894
895
896
897
898
899
900
901
902
903
904

905
906
907
908
909
910
911
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**
** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
** or a tag or branch name that identifies the check-in.



*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */
  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;               /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */

  const char *zBrName;          /* Branch name */
  DiffConfig DCfg,*pCfg;        /* Type of diff */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");







>
>
>













>







897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**
** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
** or a tag or branch name that identifies the check-in.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */
  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;               /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */
  const char *zPageHide = "ci"; /* Page that hides diffs */
  const char *zBrName;          /* Branch name */
  DiffConfig DCfg,*pCfg;        /* Type of diff */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");
1167
1168
1169
1170
1171
1172
1173






1174


1175
1176
1177
1178


1179
1180
1181
1182
1183
1184
1185
1186
  @ </div><div class="section accordion">Changes</div>
  @ <div class="accordion_panel">
  @ <div class="sectionmenu info-changes-menu">
  /* ^^^ .info-changes-menu is used by diff scroll sync */
  pCfg = construct_diff_flags(diffType, &DCfg);
  DCfg.pRe = pRe;
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";






  if( diffType!=1 ){


    @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){


    @ %z(chref("button","%R/%s/%T?diff=2%s",zPage,zName,zW))\
    @ Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R/%s/%T",zPage,zName))
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{







>
>
>
>
>
>

>
>
|



>
>
|







1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  @ </div><div class="section accordion">Changes</div>
  @ <div class="accordion_panel">
  @ <div class="sectionmenu info-changes-menu">
  /* ^^^ .info-changes-menu is used by diff scroll sync */
  pCfg = construct_diff_flags(diffType, &DCfg);
  DCfg.pRe = pRe;
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    /* Class "smb-hide-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-hide-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=0",zPageHide,zName))\
    @ Hide&nbsp;Diff</a>
  }
  if( diffType!=1 ){
    /* Class "smb-unified-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-unified-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){
    /* Class "smb-side-by-side-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-side-by-side-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=2%s",zPage,zName,zW))\
    @ Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R/%s/%T",zPage,zName))
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
1447
1448
1449
1450
1451
1452
1453














1454
1455
1456
1457
1458
1459
1460
**   dc=N            show N lines of context around each diff
**   w=BOOLEAN       ignore whitespace when computing diffs
**   nohdr           omit the description at the top of the page
**   nc              omit branch coloration from the header graph
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.














*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
**   dc=N            show N lines of context around each diff
**   w=BOOLEAN       ignore whitespace when computing diffs
**   nohdr           omit the description at the top of the page
**   nc              omit branch coloration from the header graph
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.
**
** Keyboard navigation shortcuts:
**
**    I     Show all file changes.
**    i     Hide all file changes.
**    p     Show only next file change.
**    o     Show only previous file change.
**    u     Reload page in Unified Diff mode.
**    U     Reload page in Side-By-Side Diff mode.
**    0     Reload page in Hidden Diff mode.
**    d     Reload page and set current Diff mode as default.
**
** The keyboard shortcuts also apply to /ckout, /vinfo, /ci and /fdiff
** pages, and to /info pages describing check-in information.
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;
1533
1534
1535
1536
1537
1538
1539



1540
1541
1542
1543
1544
1545
1546
    blob_appendf(&qp, "&w");
  }
  cgi_check_for_malice();
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }



  if( diffType!=2 ){
    style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
                          &qpGlob);
  }
  if( diffType!=1 ) {
    style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
  }







>
>
>







1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
    blob_appendf(&qp, "&w");
  }
  cgi_check_for_malice();
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }
  if( diffType!=0 ){
    style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b%b", &qp, &qpGlob);
  }
  if( diffType!=2 ){
    style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
                          &qpGlob);
  }
  if( diffType!=1 ) {
    style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
  }
2007
2008
2009
2010
2011
2012
2013



2014
2015
2016
2017
2018
2019
2020
**
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace



*/
void diff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;







>
>
>







2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
**
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void diff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;
3176
3177
3178
3179
3180
3181
3182



3183
3184
3185
3186
3187
3188
3189
**
** The NAME argument is any valid artifact name: an artifact hash,
** a timestamp, a tag name, etc.
**
** Because NAME can match so many different things (commit artifacts,
** wiki pages, ticket comments, forum posts...) the format of the output
** page depends on the type of artifact that NAME matches.



*/
void info_page(void){
  const char *zName;
  Blob uuid;
  int rid;
  int rc;
  int nLen;







>
>
>







3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
**
** The NAME argument is any valid artifact name: an artifact hash,
** a timestamp, a tag name, etc.
**
** Because NAME can match so many different things (commit artifacts,
** wiki pages, ticket comments, forum posts...) the format of the output
** page depends on the type of artifact that NAME matches.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts (if the NAME argument refers to a check-in).
*/
void info_page(void){
  const char *zName;
  Blob uuid;
  int rid;
  int rc;
  int nLen;