Fossil

Check-in [14ac3e8469]
Login

Check-in [14ac3e8469]

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

Overview
Comment:Reimplemented ln=... highlighting to mark the line numbers instead of the code, so that there is no interference with syntax highlighters. Adjusted two skins to use the newer line-marking CSS.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | line-number-selection
Files: files | file ages | folders
SHA3-256: 14ac3e8469f392eb917e3fd79b0863ac21ee81688b965e455ff03b70a95e09e1
User & Date: stephan 2020-08-15 03:51:17.037
Context
2020-08-15
07:41
Implemented dynamic mouse selection of source lines and clipboard tooltip to copy the line range URL. ... (check-in: 3942eb600a user: stephan tags: line-number-selection)
03:51
Reimplemented ln=... highlighting to mark the line numbers instead of the code, so that there is no interference with syntax highlighters. Adjusted two skins to use the newer line-marking CSS. ... (check-in: 14ac3e8469 user: stephan tags: line-number-selection)
2020-08-14
19:25
Merged trunk to avoid style collisions later. Changed table.numbered-lines line-height from ex units to unitless, as Mozilla recommends. ... (check-in: 41f270de75 user: stephan tags: line-number-selection)
Changes
Unified Diff Ignore Whitespace Patch
Changes to skins/eagle/css.txt.
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  font-family: "courier new";
}

div.filetreeline:hover {
  background-color: #7EA2D9;
}

div.selectedText {
  background-color: #7EA2D9;
}

.statistics-report-graph-line {
  background-color: #7EA2D9;
}








|







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  font-family: "courier new";
}

div.filetreeline:hover {
  background-color: #7EA2D9;
}

table.numbered-lines td.line-numbers span.selected-line {
  background-color: #7EA2D9;
}

.statistics-report-graph-line {
  background-color: #7EA2D9;
}

Changes to skins/xekri/css.txt.
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016


/**************************************
 * Did not encounter these
 */

/* selected lines of text within a linenumbered artifact display */
div.selectedText {
  font-weight: bold;
  color: #00f;
  background-color: #d5d5ff;
  border: 1px #00f solid;
}

/* format for missing privileges note on user setup page */
p.missingPriv {
  color: #00f;
}








|



|







998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016


/**************************************
 * Did not encounter these
 */

/* selected lines of text within a linenumbered artifact display */
table.numbered-lines td.line-numbers span.selected-line {
  font-weight: bold;
  color: #00f;
  background-color: #d5d5ff;
  border-color: #00f;
}

/* format for missing privileges note on user setup page */
p.missingPriv {
  color: #00f;
}

Changes to src/default.css.
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
}
span.usertype:before {
  content:"'";
}
span.usertype:after {
  content:"'";
}
div.selectedText {
  font-weight: bold;
  color: blue;
  background-color: #d5d5ff;
  border: 1px blue solid;
  border-top: none;
  border-bottom: none;
}
p.missingPriv {
 color: blue;
}
span.wikiruleHead {
  font-weight: bold;
}
td.tktDspLabel {







<
<
<
<
<
<
<
<







438
439
440
441
442
443
444








445
446
447
448
449
450
451
}
span.usertype:before {
  content:"'";
}
span.usertype:after {
  content:"'";
}








p.missingPriv {
 color: blue;
}
span.wikiruleHead {
  font-weight: bold;
}
td.tktDspLabel {
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
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

1213



1214

  line-height: 1.35;
  white-space: pre;
  margin: 0;
  white-space: nowrap;
  vertical-align: top;
  padding: 1em 0 0 0 /*prevents slight overlap at top */;
}
table.numbered-lines td:nth-of-type(1) > span {
  display: block;
  margin: 0;
  padding: 0;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  white-space: pre;
}
table.numbered-lines td:nth-of-type(1) > span:hover {
  background-color: #777;
  opacity: 0.25;
}
table.numbered-lines td:nth-of-type(2) {
  padding-left: 1em;
}
table.numbered-lines td:nth-of-type(2) > pre {
  margin: 0;
  padding: 0;
  overflow-x: auto;
  overflow-y: hidden /* apparently not needed, but eases my mind */;
  padding: 0 0 1em 0 /*prevents a slight underlap at bottom from triggering a scrollar */;
}
table.numbered-lines td:nth-of-type(2) > pre > code {
  margin: 0;
  padding: 0;
  white-space: pre;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
}
table.numbered-lines td:nth-of-type(2) > pre > code > * {
  box-sizing: border-box;
}
/* if div.selectedText has a top/bottom border, we need to subtract those








   from the top margin here... */

/*table.numbered-lines td:nth-of-type(2) > pre > code > div.selectedText {

  margin-top: -2px;



}*/








|









|



|


|






|







|


|
>
>
>
>
>
>
>
>
|
>
|
>
|
>
>
>
|
>
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
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
1213
1214
1215
1216
1217
1218
1219
1220
  line-height: 1.35;
  white-space: pre;
  margin: 0;
  white-space: nowrap;
  vertical-align: top;
  padding: 1em 0 0 0 /*prevents slight overlap at top */;
}
table.numbered-lines td.line-numbers > span {
  display: block;
  margin: 0;
  padding: 0;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  white-space: pre;
}
table.numbered-lines td.line-numbers > span:hover {
  background-color: #777;
  opacity: 0.25;
}
table.numbered-lines td.file-content {
  padding-left: 1em;
}
table.numbered-lines td.file-content > pre {
  margin: 0;
  padding: 0;
  overflow-x: auto;
  overflow-y: hidden /* apparently not needed, but eases my mind */;
  padding: 0 0 1em 0 /*prevents a slight underlap at bottom from triggering a scrollar */;
}
table.numbered-lines td.file-content > pre > code {
  margin: 0;
  padding: 0;
  white-space: pre;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
}
table.numbered-lines td.file-content > pre > code > * {
  box-sizing: border-box;
}
div.selectedText/*legacy*/,
table.numbered-lines td.line-numbers span.selected-line/*replacement*/ {
  font-weight: bold;
  color: blue;
  background-color: #d5d5ff;
  border: 1px blue solid;
  border-top-width: 0;
  border-bottom-width: 0;
  padding: 0;
  margin: 0;
}
table.numbered-lines td.line-numbers span.selected-line.start {
  border-top-width: 1px;
  margin-top: -1px/*restore alignment*/;
}
table.numbered-lines td.line-numbers span.selected-line.end {
  border-bottom-width: 1px;
  margin-top: -1px/*restore alignment*/;
}
Changes to src/info.c.
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040

2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063









2064

2065
2066
2067

2068
2069
2070





2071








2072


2073


2074





2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
/*
** The "z" argument is a string that contains the text of a source
** code file and nZ is its length in bytes. This routine appends that
** text to the HTTP reply with line numbering.
**
** zName is the content's file name, if any (it may be NULL). If that
** name contains a '.' then the part after the final '.' is used as
** the X part of a "language-X" CSS class on the generate CODE block.
**
** zLn is the ?ln= parameter for the HTTP query.  If there is an argument,
** then highlight that line number and scroll to it once the page loads.
** If there are two line numbers, highlight the range of lines.
** Multiple ranges can be highlighed by adding additional line numbers
** separated by a non-digit character (also not one of [-,.]).
*/
void output_text_with_line_numbers(
  const char *z,
  int nZ,
  const char *zName,
  const char *zLn
){
  int iStart, iEnd;    /* Start and end of region to highlight */
  int n = 0;           /* Current line number */
  int i = 0;           /* Loop index */
  int iTop = 0;        /* Scroll so that this line is on top of screen. */
  int nLine = 0;

  const char *zExt = file_extension(zName);
  Stmt q;

  iStart = iEnd = atoi(zLn);
  db_multi_exec(
    "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
  if( iStart>0 ){
    do{
      while( fossil_isdigit(zLn[i]) ) i++;
      if( zLn[i]==',' || zLn[i]=='-' || zLn[i]=='.' ){
        i++;
        while( zLn[i]=='.' ){ i++; }
        iEnd = atoi(&zLn[i]);
        while( fossil_isdigit(zLn[i]) ) i++;
      }
      while( fossil_isdigit(zLn[i]) ) i++;
      if( iEnd<iStart ) iEnd = iStart;
      db_multi_exec(
        "INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd
      );

      iStart = iEnd = atoi(&zLn[i++]);
    }while( zLn[i] && iStart && iEnd );
  }









  db_prepare(&q, "SELECT min(iStart), max(iEnd) FROM lnos");

  if( db_step(&q)==SQLITE_ROW ){
    iStart = db_column_int(&q, 0);
    iEnd = db_column_int(&q, 1);

    iTop = iStart - 15 + (iEnd-iStart)/4;
    if( iTop>iStart - 2 ) iTop = iStart-2;
  }





  db_finalize(&q);








  CX("<table class='numbered-lines'><tbody><tr><td>");


  count_lines(z, nZ, &nLine);


  for(i=0; i < nLine; ++i){





    CX("<span>%6d</span>", i+1);
  }
  CX("</td><td><pre>");
  if(zExt && *zExt){
    CX("<code class='language-%h'>",zExt);
  }else{
    CX("<code>");
  }
  assert(!n);
  while( z[0] ){
    n++;
    db_prepare(&q,
      "SELECT min(iStart), max(iEnd) FROM lnos"
      " WHERE iStart <= %d AND iEnd >= %d", n, n);
    if( db_step(&q)==SQLITE_ROW ){
      iStart = db_column_int(&q, 0);
      iEnd = db_column_int(&q, 1);
    }
    db_finalize(&q);
    for(i=0; z[i] && z[i]!='\n'; i++){}
    if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
    if( n==iStart ){
      cgi_append_content("<div class=\"selectedText\">",-1);
    }
    if( i>0 ){
      char *zHtml = htmlize(z, i);
      cgi_append_content(zHtml, -1);
      fossil_free(zHtml);
    }
    if( n==iTop ) cgi_append_content("</span>", -1);
    if( n==iEnd ) cgi_append_content("</div>", -1);
    else cgi_append_content("\n", 1);
    z += i;
    if( z[0]=='\n' ) z++;
  }
  if( n<iEnd ) cgi_printf("</div>");
  CX("</code></pre></td></tr></tbody></table>\n");
  if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
    builtin_request_js("scroll.js");
  }
  builtin_request_js("fossil.numbered-lines.js");
}








|

















|
>




















>



>
>
>
>
>
>
>
>
>
|
>
|
|
|
>
|
|
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
|
>
>
|
>
>
>
>
>
|

|

|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
|
<
<
<
<
<
<
|







2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115




















2116

2117






2118
2119
2120
2121
2122
2123
2124
2125
/*
** The "z" argument is a string that contains the text of a source
** code file and nZ is its length in bytes. This routine appends that
** text to the HTTP reply with line numbering.
**
** zName is the content's file name, if any (it may be NULL). If that
** name contains a '.' then the part after the final '.' is used as
** the X part of a "language-X" CSS class on the generated CODE block.
**
** zLn is the ?ln= parameter for the HTTP query.  If there is an argument,
** then highlight that line number and scroll to it once the page loads.
** If there are two line numbers, highlight the range of lines.
** Multiple ranges can be highlighed by adding additional line numbers
** separated by a non-digit character (also not one of [-,.]).
*/
void output_text_with_line_numbers(
  const char *z,
  int nZ,
  const char *zName,
  const char *zLn
){
  int iStart, iEnd;    /* Start and end of region to highlight */
  int n = 0;           /* Current line number */
  int i = 0;           /* Loop index */
  int iTop = 0;        /* Scroll so that this line is on top of screen. */
  int nLine = 0;       /* content line count */
  int nSpans = 0;      /* number of distinct zLn spans */
  const char *zExt = file_extension(zName);
  Stmt q;

  iStart = iEnd = atoi(zLn);
  db_multi_exec(
    "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
  if( iStart>0 ){
    do{
      while( fossil_isdigit(zLn[i]) ) i++;
      if( zLn[i]==',' || zLn[i]=='-' || zLn[i]=='.' ){
        i++;
        while( zLn[i]=='.' ){ i++; }
        iEnd = atoi(&zLn[i]);
        while( fossil_isdigit(zLn[i]) ) i++;
      }
      while( fossil_isdigit(zLn[i]) ) i++;
      if( iEnd<iStart ) iEnd = iStart;
      db_multi_exec(
        "INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd
      );
      ++nSpans;
      iStart = iEnd = atoi(&zLn[i++]);
    }while( zLn[i] && iStart && iEnd );
  }
  /*cgi_printf("<!-- ln span count=%d -->", nSpans);*/
  cgi_append_content("<table class='numbered-lines'><tbody>"
                     "<tr><td class='line-numbers'>", -1);
  iStart = iEnd = 0;
  count_lines(z, nZ, &nLine);
  for( n=1 ; n<=nLine; ++n ){
    const char * zAttr = "";
    const char * zId = "";
    if(nSpans>0 && iEnd==0){/*Grab the next range of zLn marking*/
      db_prepare(&q, "SELECT iStart, iEnd FROM lnos "
                 "WHERE iStart >= %d ORDER BY iStart", n);
      if( db_step(&q)==SQLITE_ROW ){
        iStart = db_column_int(&q, 0);
        iEnd = db_column_int(&q, 1);
        if(!iTop){
          iTop = iStart - 15 + (iEnd-iStart)/4;
          if( iTop>iStart - 2 ) iTop = iStart-2;
        }
      }else{
        /* Note that overlapping multi-spans, e.g. 10-15+12-20,
           can cause us to miss a row. */
        iStart = iEnd = 0;
      }
      db_finalize(&q);
      --nSpans;
      /*cgi_printf("<!-- iStart=%d, iEnd=%d -->", iStart, iEnd);*/
    }
    if(n==iTop) {
      zId = " id='scrollToMe'";
    }
    if(n==iStart){/*Figure out which CSS class(es) this line needs...*/
      if(n==iEnd){
        zAttr = " class='selected-line start end'";
        iEnd = 0;
      }else{
        zAttr = " class='selected-line start'";
      }
      iStart = 0;
    }else if(n==iEnd){
      zAttr = " class='selected-line end'";
      iEnd = 0;
    }else if( n>iStart && n<iEnd ){
      zAttr = " class='selected-line'";
    }
    cgi_printf("<span%s%s>%6d</span>", zId, zAttr, n);
  }
  cgi_append_content("</td><td class='file-content'><pre>",-1);
  if(zExt && *zExt){
    cgi_printf("<code class='language-%h'>",zExt);
  }else{




















    cgi_append_content("<code>", -1);

  }






  cgi_printf("%.*h", nZ, z);
  CX("</code></pre></td></tr></tbody></table>\n");
  if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
    builtin_request_js("scroll.js");
  }
  builtin_request_js("fossil.numbered-lines.js");
}