Fossil SCM

Changes line-numbered output to make line numbers selectable, as discussed in [https://fossil-scm.org/forum/forumpost/dc3da10590]. A couple decisions are needed before deciding whether to merge.

stephan 2020-08-14 11:53 trunk
Commit ec73edd4d09dc7c9f2f3e766d2fa4274b32bf7dcb31739c2d77511b1ab0d93c4
+2 -1
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130130
wiki_render_by_mimetype(pContent, zMime);
131131
break;
132132
default:{
133133
const char *zContent = blob_str(pContent);
134134
if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135
- output_text_with_line_numbers(zContent, "on");
135
+ output_text_with_line_numbers(zContent,
136
+ blob_size(pContent), "on");
136137
}else{
137138
const char *zExt = strrchr(zName,'.');
138139
if(zExt && zExt[1]){
139140
CX("<pre><code class='language-%s'>%h</code></pre>",
140141
zExt+1, zContent);
141142
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130 wiki_render_by_mimetype(pContent, zMime);
131 break;
132 default:{
133 const char *zContent = blob_str(pContent);
134 if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135 output_text_with_line_numbers(zContent, "on");
 
136 }else{
137 const char *zExt = strrchr(zName,'.');
138 if(zExt && zExt[1]){
139 CX("<pre><code class='language-%s'>%h</code></pre>",
140 zExt+1, zContent);
141
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130 wiki_render_by_mimetype(pContent, zMime);
131 break;
132 default:{
133 const char *zContent = blob_str(pContent);
134 if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135 output_text_with_line_numbers(zContent,
136 blob_size(pContent), "on");
137 }else{
138 const char *zExt = strrchr(zName,'.');
139 if(zExt && zExt[1]){
140 CX("<pre><code class='language-%s'>%h</code></pre>",
141 zExt+1, zContent);
142
+1 -1
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617617
const char *z;
618618
content_get(ridSrc, &attach);
619619
blob_to_utf8_no_bom(&attach, 0);
620620
z = blob_str(&attach);
621621
if( zLn ){
622
- output_text_with_line_numbers(z, zLn);
622
+ output_text_with_line_numbers(z, blob_size(&attach), zLn);
623623
}else{
624624
@ <pre>
625625
@ %h(z)
626626
@ </pre>
627627
}
628628
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617 const char *z;
618 content_get(ridSrc, &attach);
619 blob_to_utf8_no_bom(&attach, 0);
620 z = blob_str(&attach);
621 if( zLn ){
622 output_text_with_line_numbers(z, zLn);
623 }else{
624 @ <pre>
625 @ %h(z)
626 @ </pre>
627 }
628
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617 const char *z;
618 content_get(ridSrc, &attach);
619 blob_to_utf8_no_bom(&attach, 0);
620 z = blob_str(&attach);
621 if( zLn ){
622 output_text_with_line_numbers(z, blob_size(&attach), zLn);
623 }else{
624 @ <pre>
625 @ %h(z)
626 @ </pre>
627 }
628
--- src/default.css
+++ src/default.css
@@ -445,10 +445,12 @@
445445
div.selectedText {
446446
font-weight: bold;
447447
color: blue;
448448
background-color: #d5d5ff;
449449
border: 1px blue solid;
450
+ border-top: none;
451
+ border-bottom: none;
450452
}
451453
p.missingPriv {
452454
color: blue;
453455
}
454456
span.wikiruleHead {
@@ -1138,5 +1140,55 @@
11381140
.input-with-label > label {
11391141
font-weight: initial;
11401142
margin: 0 0.25em 0 0.25em;
11411143
vertical-align: middle;
11421144
}
1145
+
1146
+table.numbered-lines td {
1147
+ font-family: monospace;
1148
+ line-height: 2.8ex;
1149
+ white-space: pre;
1150
+ margin: 0;
1151
+ white-space: nowrap;
1152
+ vertical-align: top;
1153
+ padding: 1em 0 0 0 /*prevents slight overlap at top */;
1154
+}
1155
+table.numbered-lines td:nth-of-type(1) > span {
1156
+ display: block;
1157
+ margin: 0;
1158
+ padding: 0;
1159
+ line-height: inherit;
1160
+ font-size: inherit;
1161
+ font-family: inherit;
1162
+ cursor: pointer;
1163
+ white-space: pre;
1164
+}
1165
+table.numbered-lines td:nth-of-type(1) > span:hover {
1166
+ background-color: #777;
1167
+ opacity: 0.25;
1168
+}
1169
+table.numbered-lines td:nth-of-type(2) {
1170
+ padding-left: 1em;
1171
+}
1172
+table.numbered-lines td:nth-of-type(2) > pre {
1173
+ margin: 0;
1174
+ padding: 0;
1175
+ overflow-x: auto;
1176
+ overflow-y: hidden /* apparently not needed, but eases my mind */;
1177
+ padding: 0 0 1em 0 /*prevents a slight underlap at bottom from triggering a scrollar */;
1178
+}
1179
+table.numbered-lines td:nth-of-type(2) > pre > code {
1180
+ margin: 0;
1181
+ padding: 0;
1182
+ white-space: pre;
1183
+ line-height: inherit;
1184
+ font-size: inherit;
1185
+ font-family: inherit;
1186
+}
1187
+table.numbered-lines td:nth-of-type(2) > pre > code > * {
1188
+ box-sizing: border-box;
1189
+}
1190
+/* if div.selectedText has a top/bottom border, we need to subtract those
1191
+ from the top margin here... */
1192
+/*table.numbered-lines td:nth-of-type(2) > pre > code > div.selectedText {
1193
+ margin-top: -2px;
1194
+}*/
11431195
--- src/default.css
+++ src/default.css
@@ -445,10 +445,12 @@
445 div.selectedText {
446 font-weight: bold;
447 color: blue;
448 background-color: #d5d5ff;
449 border: 1px blue solid;
 
 
450 }
451 p.missingPriv {
452 color: blue;
453 }
454 span.wikiruleHead {
@@ -1138,5 +1140,55 @@
1138 .input-with-label > label {
1139 font-weight: initial;
1140 margin: 0 0.25em 0 0.25em;
1141 vertical-align: middle;
1142 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1143
--- src/default.css
+++ src/default.css
@@ -445,10 +445,12 @@
445 div.selectedText {
446 font-weight: bold;
447 color: blue;
448 background-color: #d5d5ff;
449 border: 1px blue solid;
450 border-top: none;
451 border-bottom: none;
452 }
453 p.missingPriv {
454 color: blue;
455 }
456 span.wikiruleHead {
@@ -1138,5 +1140,55 @@
1140 .input-with-label > label {
1141 font-weight: initial;
1142 margin: 0 0.25em 0 0.25em;
1143 vertical-align: middle;
1144 }
1145
1146 table.numbered-lines td {
1147 font-family: monospace;
1148 line-height: 2.8ex;
1149 white-space: pre;
1150 margin: 0;
1151 white-space: nowrap;
1152 vertical-align: top;
1153 padding: 1em 0 0 0 /*prevents slight overlap at top */;
1154 }
1155 table.numbered-lines td:nth-of-type(1) > span {
1156 display: block;
1157 margin: 0;
1158 padding: 0;
1159 line-height: inherit;
1160 font-size: inherit;
1161 font-family: inherit;
1162 cursor: pointer;
1163 white-space: pre;
1164 }
1165 table.numbered-lines td:nth-of-type(1) > span:hover {
1166 background-color: #777;
1167 opacity: 0.25;
1168 }
1169 table.numbered-lines td:nth-of-type(2) {
1170 padding-left: 1em;
1171 }
1172 table.numbered-lines td:nth-of-type(2) > pre {
1173 margin: 0;
1174 padding: 0;
1175 overflow-x: auto;
1176 overflow-y: hidden /* apparently not needed, but eases my mind */;
1177 padding: 0 0 1em 0 /*prevents a slight underlap at bottom from triggering a scrollar */;
1178 }
1179 table.numbered-lines td:nth-of-type(2) > pre > code {
1180 margin: 0;
1181 padding: 0;
1182 white-space: pre;
1183 line-height: inherit;
1184 font-size: inherit;
1185 font-family: inherit;
1186 }
1187 table.numbered-lines td:nth-of-type(2) > pre > code > * {
1188 box-sizing: border-box;
1189 }
1190 /* if div.selectedText has a top/bottom border, we need to subtract those
1191 from the top margin here... */
1192 /*table.numbered-lines td:nth-of-type(2) > pre > code > div.selectedText {
1193 margin-top: -2px;
1194 }*/
1195
+1 -1
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125125
** in the count even if it lacks the \n terminator. If an empty string
126126
** is specified, the number of lines is zero. For the purposes of this
127127
** function, a string is considered empty if it contains no characters
128128
** -OR- it contains only NUL characters.
129129
*/
130
-static int count_lines(
130
+int count_lines(
131131
const char *z,
132132
int n,
133133
int *pnLine
134134
){
135135
int nLine;
136136
137137
ADDED src/fossil.numbered-lines.js
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125 ** in the count even if it lacks the \n terminator. If an empty string
126 ** is specified, the number of lines is zero. For the purposes of this
127 ** function, a string is considered empty if it contains no characters
128 ** -OR- it contains only NUL characters.
129 */
130 static int count_lines(
131 const char *z,
132 int n,
133 int *pnLine
134 ){
135 int nLine;
136
137 DDED src/fossil.numbered-lines.js
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125 ** in the count even if it lacks the \n terminator. If an empty string
126 ** is specified, the number of lines is zero. For the purposes of this
127 ** function, a string is considered empty if it contains no characters
128 ** -OR- it contains only NUL characters.
129 */
130 int count_lines(
131 const char *z,
132 int n,
133 int *pnLine
134 ){
135 int nLine;
136
137 DDED src/fossil.numbered-lines.js
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,40 @@
1
+(function callee(arg){
2
+ /* JSelse if(!arg){tion callee(arg){
3
+e(arg){
4
+ /*
5
+ JSfossil',
6
+ ppend(function1M@Y5,1:rx@ZS,1:
7
+G@eW,1p@_~,11:unselect line*/
8
+ //console.debug("Unselected line #"+ln);
9
+Q@eU,Z@cT,2g@dG,c://console.debug("Selected range: ",rng)J@cU,K:2;
10
+ }
11
+ ;
12
+ else if(tbl.length>1){
13
+f(1l@kP,n@mBreturn;
14
+ }else{
15
+gs =urn y - this.e.crgs =urn y - this.e.clientHeight/2;
16
+ console.debug("(function callee(arg){
17
+ /*
18
+ JSelse if(!arg){tion callee(arg){
19
+ /*
20
+ JS(function callee(arg){
21
+ /*
22
+ JSfossil',
23
+ (F.toast("Copied: ",D.append(function callee(arg){
24
+ /*
25
+ JSelse if(!arg){tion callee(artooltip>x,
26
+ adjustY: (y)=>y9F@Lz,1M@Y5,1:rx@ZS,1:
27
+G@eW,1p@_~,11:unselect line*/
28
+ //console.debug("Unselected line #"+ln);
29
+Q@eU,Z@cT,2g@dG,c://console.debug("Selected range: ",rng)J@cU,K:2;
30
+ }
31
+ }
32
+ h@WA,9:.forEach(7@ED,p@XB,K:);
33
+ if(f.mode>0){y@j0,7:lineTipa@qr,D: const spansU@W8,D:');
34
+ if(1l@kP,n@mB,17@m~,7:if(i===G@bW,1t@oz,2:;
35
+H@f0,N@RT,Q@r~,1IHlU4;function(xreturn x + 20;
36
+ },
37
+ adjustY: function(y){
38
+ return y - this.e.clientHeight/2;
39
+ }addClass(D.span(), 'copy-button');
40
+ const link = D.attr(D.span(), 'id', 'fossil-ln-link'lineTip.show(ev.clientX, ev.clientY
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,40 @@
1 (function callee(arg){
2 /* JSelse if(!arg){tion callee(arg){
3 e(arg){
4 /*
5 JSfossil',
6 ppend(function1M@Y5,1:rx@ZS,1:
7 G@eW,1p@_~,11:unselect line*/
8 //console.debug("Unselected line #"+ln);
9 Q@eU,Z@cT,2g@dG,c://console.debug("Selected range: ",rng)J@cU,K:2;
10 }
11 ;
12 else if(tbl.length>1){
13 f(1l@kP,n@mBreturn;
14 }else{
15 gs =urn y - this.e.crgs =urn y - this.e.clientHeight/2;
16 console.debug("(function callee(arg){
17 /*
18 JSelse if(!arg){tion callee(arg){
19 /*
20 JS(function callee(arg){
21 /*
22 JSfossil',
23 (F.toast("Copied: ",D.append(function callee(arg){
24 /*
25 JSelse if(!arg){tion callee(artooltip>x,
26 adjustY: (y)=>y9F@Lz,1M@Y5,1:rx@ZS,1:
27 G@eW,1p@_~,11:unselect line*/
28 //console.debug("Unselected line #"+ln);
29 Q@eU,Z@cT,2g@dG,c://console.debug("Selected range: ",rng)J@cU,K:2;
30 }
31 }
32 h@WA,9:.forEach(7@ED,p@XB,K:);
33 if(f.mode>0){y@j0,7:lineTipa@qr,D: const spansU@W8,D:');
34 if(1l@kP,n@mB,17@m~,7:if(i===G@bW,1t@oz,2:;
35 H@f0,N@RT,Q@r~,1IHlU4;function(xreturn x + 20;
36 },
37 adjustY: function(y){
38 return y - this.e.clientHeight/2;
39 }addClass(D.span(), 'copy-button');
40 const link = D.attr(D.span(), 'id', 'fossil-ln-link'lineTip.show(ev.clientX, ev.clientY
+40 -6
--- src/info.c
+++ src/info.c
@@ -2011,27 +2011,30 @@
20112011
manifest_destroy(pManifest);
20122012
return rid;
20132013
}
20142014
20152015
/*
2016
-** The "z" argument is a string that contains the text of a source code
2017
-** file. This routine appends that text to the HTTP reply with line numbering.
2016
+** The "z" argument is a string that contains the text of a source
2017
+** code file and nZ is its length in bytes. This routine appends that
2018
+** text to the HTTP reply with line numbering.
20182019
**
20192020
** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
20202021
** then highlight that line number and scroll to it once the page loads.
20212022
** If there are two line numbers, highlight the range of lines.
20222023
** Multiple ranges can be highlighed by adding additional line numbers
20232024
** separated by a non-digit character (also not one of [-,.]).
20242025
*/
20252026
void output_text_with_line_numbers(
20262027
const char *z,
2028
+ int nZ,
20272029
const char *zLn
20282030
){
20292031
int iStart, iEnd; /* Start and end of region to highlight */
20302032
int n = 0; /* Current line number */
20312033
int i = 0; /* Loop index */
20322034
int iTop = 0; /* Scroll so that this line is on top of screen. */
2035
+ int nLine = 0;
20332036
Stmt q;
20342037
20352038
iStart = iEnd = atoi(zLn);
20362039
db_multi_exec(
20372040
"CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2058,11 +2061,17 @@
20582061
iEnd = db_column_int(&q, 1);
20592062
iTop = iStart - 15 + (iEnd-iStart)/4;
20602063
if( iTop>iStart - 2 ) iTop = iStart-2;
20612064
}
20622065
db_finalize(&q);
2063
- @ <pre>
2066
+ CX("<table class='numbered-lines'><tbody><tr><td>");
2067
+ count_lines(z, nZ, &nLine);
2068
+ for(i=0; i < nLine; ++i){
2069
+ CX("<span>%6d</span>", i+1);
2070
+ }
2071
+ CX("</td><td><pre><code>");
2072
+ assert(!n);
20642073
while( z[0] ){
20652074
n++;
20662075
db_prepare(&q,
20672076
"SELECT min(iStart), max(iEnd) FROM lnos"
20682077
" WHERE iStart <= %d AND iEnd >= %d", n, n);
@@ -2074,11 +2083,10 @@
20742083
for(i=0; z[i] && z[i]!='\n'; i++){}
20752084
if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
20762085
if( n==iStart ){
20772086
cgi_append_content("<div class=\"selectedText\">",-1);
20782087
}
2079
- cgi_printf("%6d ", n);
20802088
if( i>0 ){
20812089
char *zHtml = htmlize(z, i);
20822090
cgi_append_content(zHtml, -1);
20832091
fossil_free(zHtml);
20842092
}
@@ -2087,16 +2095,42 @@
20872095
else cgi_append_content("\n", 1);
20882096
z += i;
20892097
if( z[0]=='\n' ) z++;
20902098
}
20912099
if( n<iEnd ) cgi_printf("</div>");
2092
- @ </pre>
2100
+ CX("</code></pre></td></tr></tbody></table>\n");
20932101
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
20942102
builtin_request_js("scroll.js");
20952103
}
2104
+ builtin_request_js("fossil.numbered-lines.js");
20962105
}
20972106
2107
+/*
2108
+** COMMAND: test-line-numbers
2109
+**
2110
+** Usage: %fossil test-line-numbers FILE ?LN-SPEC?
2111
+**
2112
+*/
2113
+void cmd_test_line_numbers(void){
2114
+ Blob content = empty_blob;
2115
+ const char * zLn = "";
2116
+ const char * zFilename = 0;
2117
+
2118
+ if(g.argc < 3){
2119
+ usage("FILE");
2120
+ }else if(g.argc>3){
2121
+ zLn = g.argv[3];
2122
+ }
2123
+ db_find_and_open_repository(0,0);
2124
+ zFilename = g.argv[2];
2125
+ fossil_print("%s %s\n", zFilename, zLn);
2126
+
2127
+ blob_read_from_file(&content, zFilename, ExtFILE);
2128
+ output_text_with_line_numbers(blob_str(&content), blob_size(&content), zLn);
2129
+ blob_reset(&content);
2130
+ fossil_print("%b\n", cgi_output_blob());
2131
+}
20982132
20992133
/*
21002134
** WEBPAGE: artifact
21012135
** WEBPAGE: file
21022136
** WEBPAGE: whatis
@@ -2398,11 +2432,11 @@
23982432
" WHERE filename.fnid=mlink.fnid"
23992433
" AND mlink.fid=%d",
24002434
rid);
24012435
zExt = zFileName ? strrchr(zFileName, '.') : 0;
24022436
if( zLn ){
2403
- output_text_with_line_numbers(z, zLn);
2437
+ output_text_with_line_numbers(z, blob_size(&content), zLn);
24042438
}else if( zExt && zExt[1] ){
24052439
@ <pre>
24062440
@ <code class="language-%s(zExt+1)">%h(z)</code>
24072441
@ </pre>
24082442
}else{
24092443
--- src/info.c
+++ src/info.c
@@ -2011,27 +2011,30 @@
2011 manifest_destroy(pManifest);
2012 return rid;
2013 }
2014
2015 /*
2016 ** The "z" argument is a string that contains the text of a source code
2017 ** file. This routine appends that text to the HTTP reply with line numbering.
 
2018 **
2019 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
2020 ** then highlight that line number and scroll to it once the page loads.
2021 ** If there are two line numbers, highlight the range of lines.
2022 ** Multiple ranges can be highlighed by adding additional line numbers
2023 ** separated by a non-digit character (also not one of [-,.]).
2024 */
2025 void output_text_with_line_numbers(
2026 const char *z,
 
2027 const char *zLn
2028 ){
2029 int iStart, iEnd; /* Start and end of region to highlight */
2030 int n = 0; /* Current line number */
2031 int i = 0; /* Loop index */
2032 int iTop = 0; /* Scroll so that this line is on top of screen. */
 
2033 Stmt q;
2034
2035 iStart = iEnd = atoi(zLn);
2036 db_multi_exec(
2037 "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2058,11 +2061,17 @@
2058 iEnd = db_column_int(&q, 1);
2059 iTop = iStart - 15 + (iEnd-iStart)/4;
2060 if( iTop>iStart - 2 ) iTop = iStart-2;
2061 }
2062 db_finalize(&q);
2063 @ <pre>
 
 
 
 
 
 
2064 while( z[0] ){
2065 n++;
2066 db_prepare(&q,
2067 "SELECT min(iStart), max(iEnd) FROM lnos"
2068 " WHERE iStart <= %d AND iEnd >= %d", n, n);
@@ -2074,11 +2083,10 @@
2074 for(i=0; z[i] && z[i]!='\n'; i++){}
2075 if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
2076 if( n==iStart ){
2077 cgi_append_content("<div class=\"selectedText\">",-1);
2078 }
2079 cgi_printf("%6d ", n);
2080 if( i>0 ){
2081 char *zHtml = htmlize(z, i);
2082 cgi_append_content(zHtml, -1);
2083 fossil_free(zHtml);
2084 }
@@ -2087,16 +2095,42 @@
2087 else cgi_append_content("\n", 1);
2088 z += i;
2089 if( z[0]=='\n' ) z++;
2090 }
2091 if( n<iEnd ) cgi_printf("</div>");
2092 @ </pre>
2093 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2094 builtin_request_js("scroll.js");
2095 }
 
2096 }
2097
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2098
2099 /*
2100 ** WEBPAGE: artifact
2101 ** WEBPAGE: file
2102 ** WEBPAGE: whatis
@@ -2398,11 +2432,11 @@
2398 " WHERE filename.fnid=mlink.fnid"
2399 " AND mlink.fid=%d",
2400 rid);
2401 zExt = zFileName ? strrchr(zFileName, '.') : 0;
2402 if( zLn ){
2403 output_text_with_line_numbers(z, zLn);
2404 }else if( zExt && zExt[1] ){
2405 @ <pre>
2406 @ <code class="language-%s(zExt+1)">%h(z)</code>
2407 @ </pre>
2408 }else{
2409
--- src/info.c
+++ src/info.c
@@ -2011,27 +2011,30 @@
2011 manifest_destroy(pManifest);
2012 return rid;
2013 }
2014
2015 /*
2016 ** The "z" argument is a string that contains the text of a source
2017 ** code file and nZ is its length in bytes. This routine appends that
2018 ** text to the HTTP reply with line numbering.
2019 **
2020 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
2021 ** then highlight that line number and scroll to it once the page loads.
2022 ** If there are two line numbers, highlight the range of lines.
2023 ** Multiple ranges can be highlighed by adding additional line numbers
2024 ** separated by a non-digit character (also not one of [-,.]).
2025 */
2026 void output_text_with_line_numbers(
2027 const char *z,
2028 int nZ,
2029 const char *zLn
2030 ){
2031 int iStart, iEnd; /* Start and end of region to highlight */
2032 int n = 0; /* Current line number */
2033 int i = 0; /* Loop index */
2034 int iTop = 0; /* Scroll so that this line is on top of screen. */
2035 int nLine = 0;
2036 Stmt q;
2037
2038 iStart = iEnd = atoi(zLn);
2039 db_multi_exec(
2040 "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2058,11 +2061,17 @@
2061 iEnd = db_column_int(&q, 1);
2062 iTop = iStart - 15 + (iEnd-iStart)/4;
2063 if( iTop>iStart - 2 ) iTop = iStart-2;
2064 }
2065 db_finalize(&q);
2066 CX("<table class='numbered-lines'><tbody><tr><td>");
2067 count_lines(z, nZ, &nLine);
2068 for(i=0; i < nLine; ++i){
2069 CX("<span>%6d</span>", i+1);
2070 }
2071 CX("</td><td><pre><code>");
2072 assert(!n);
2073 while( z[0] ){
2074 n++;
2075 db_prepare(&q,
2076 "SELECT min(iStart), max(iEnd) FROM lnos"
2077 " WHERE iStart <= %d AND iEnd >= %d", n, n);
@@ -2074,11 +2083,10 @@
2083 for(i=0; z[i] && z[i]!='\n'; i++){}
2084 if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
2085 if( n==iStart ){
2086 cgi_append_content("<div class=\"selectedText\">",-1);
2087 }
 
2088 if( i>0 ){
2089 char *zHtml = htmlize(z, i);
2090 cgi_append_content(zHtml, -1);
2091 fossil_free(zHtml);
2092 }
@@ -2087,16 +2095,42 @@
2095 else cgi_append_content("\n", 1);
2096 z += i;
2097 if( z[0]=='\n' ) z++;
2098 }
2099 if( n<iEnd ) cgi_printf("</div>");
2100 CX("</code></pre></td></tr></tbody></table>\n");
2101 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2102 builtin_request_js("scroll.js");
2103 }
2104 builtin_request_js("fossil.numbered-lines.js");
2105 }
2106
2107 /*
2108 ** COMMAND: test-line-numbers
2109 **
2110 ** Usage: %fossil test-line-numbers FILE ?LN-SPEC?
2111 **
2112 */
2113 void cmd_test_line_numbers(void){
2114 Blob content = empty_blob;
2115 const char * zLn = "";
2116 const char * zFilename = 0;
2117
2118 if(g.argc < 3){
2119 usage("FILE");
2120 }else if(g.argc>3){
2121 zLn = g.argv[3];
2122 }
2123 db_find_and_open_repository(0,0);
2124 zFilename = g.argv[2];
2125 fossil_print("%s %s\n", zFilename, zLn);
2126
2127 blob_read_from_file(&content, zFilename, ExtFILE);
2128 output_text_with_line_numbers(blob_str(&content), blob_size(&content), zLn);
2129 blob_reset(&content);
2130 fossil_print("%b\n", cgi_output_blob());
2131 }
2132
2133 /*
2134 ** WEBPAGE: artifact
2135 ** WEBPAGE: file
2136 ** WEBPAGE: whatis
@@ -2398,11 +2432,11 @@
2432 " WHERE filename.fnid=mlink.fnid"
2433 " AND mlink.fid=%d",
2434 rid);
2435 zExt = zFileName ? strrchr(zFileName, '.') : 0;
2436 if( zLn ){
2437 output_text_with_line_numbers(z, blob_size(&content), zLn);
2438 }else if( zExt && zExt[1] ){
2439 @ <pre>
2440 @ <code class="language-%s(zExt+1)">%h(z)</code>
2441 @ </pre>
2442 }else{
2443
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225225
$(SRCDIR)/forum.js \
226226
$(SRCDIR)/fossil.bootstrap.js \
227227
$(SRCDIR)/fossil.confirmer.js \
228228
$(SRCDIR)/fossil.dom.js \
229229
$(SRCDIR)/fossil.fetch.js \
230
+ $(SRCDIR)/fossil.numbered-lines.js \
230231
$(SRCDIR)/fossil.page.fileedit.js \
231232
$(SRCDIR)/fossil.page.forumpost.js \
232233
$(SRCDIR)/fossil.page.wikiedit.js \
233234
$(SRCDIR)/fossil.storage.js \
234235
$(SRCDIR)/fossil.tabs.js \
235236
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225 $(SRCDIR)/forum.js \
226 $(SRCDIR)/fossil.bootstrap.js \
227 $(SRCDIR)/fossil.confirmer.js \
228 $(SRCDIR)/fossil.dom.js \
229 $(SRCDIR)/fossil.fetch.js \
 
230 $(SRCDIR)/fossil.page.fileedit.js \
231 $(SRCDIR)/fossil.page.forumpost.js \
232 $(SRCDIR)/fossil.page.wikiedit.js \
233 $(SRCDIR)/fossil.storage.js \
234 $(SRCDIR)/fossil.tabs.js \
235
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225 $(SRCDIR)/forum.js \
226 $(SRCDIR)/fossil.bootstrap.js \
227 $(SRCDIR)/fossil.confirmer.js \
228 $(SRCDIR)/fossil.dom.js \
229 $(SRCDIR)/fossil.fetch.js \
230 $(SRCDIR)/fossil.numbered-lines.js \
231 $(SRCDIR)/fossil.page.fileedit.js \
232 $(SRCDIR)/fossil.page.forumpost.js \
233 $(SRCDIR)/fossil.page.wikiedit.js \
234 $(SRCDIR)/fossil.storage.js \
235 $(SRCDIR)/fossil.tabs.js \
236
+1 -1
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
11
/* Cause the page to scroll so that the #scrollToMe is visible */
2
-document.getElementById('scrollToMe').scrollIntoView(true);
2
+(document.getElementById('scrollToMe')||document.body).scrollIntoView(true);
33
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
1 /* Cause the page to scroll so that the #scrollToMe is visible */
2 document.getElementById('scrollToMe').scrollIntoView(true);
3
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
1 /* Cause the page to scroll so that the #scrollToMe is visible */
2 (document.getElementById('scrollToMe')||document.body).scrollIntoView(true);
3
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -637,10 +637,11 @@
637637
$(SRCDIR)/forum.js \
638638
$(SRCDIR)/fossil.bootstrap.js \
639639
$(SRCDIR)/fossil.confirmer.js \
640640
$(SRCDIR)/fossil.dom.js \
641641
$(SRCDIR)/fossil.fetch.js \
642
+ $(SRCDIR)/fossil.numbered-lines.js \
642643
$(SRCDIR)/fossil.page.fileedit.js \
643644
$(SRCDIR)/fossil.page.forumpost.js \
644645
$(SRCDIR)/fossil.page.wikiedit.js \
645646
$(SRCDIR)/fossil.storage.js \
646647
$(SRCDIR)/fossil.tabs.js \
647648
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -637,10 +637,11 @@
637 $(SRCDIR)/forum.js \
638 $(SRCDIR)/fossil.bootstrap.js \
639 $(SRCDIR)/fossil.confirmer.js \
640 $(SRCDIR)/fossil.dom.js \
641 $(SRCDIR)/fossil.fetch.js \
 
642 $(SRCDIR)/fossil.page.fileedit.js \
643 $(SRCDIR)/fossil.page.forumpost.js \
644 $(SRCDIR)/fossil.page.wikiedit.js \
645 $(SRCDIR)/fossil.storage.js \
646 $(SRCDIR)/fossil.tabs.js \
647
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -637,10 +637,11 @@
637 $(SRCDIR)/forum.js \
638 $(SRCDIR)/fossil.bootstrap.js \
639 $(SRCDIR)/fossil.confirmer.js \
640 $(SRCDIR)/fossil.dom.js \
641 $(SRCDIR)/fossil.fetch.js \
642 $(SRCDIR)/fossil.numbered-lines.js \
643 $(SRCDIR)/fossil.page.fileedit.js \
644 $(SRCDIR)/fossil.page.forumpost.js \
645 $(SRCDIR)/fossil.page.wikiedit.js \
646 $(SRCDIR)/fossil.storage.js \
647 $(SRCDIR)/fossil.tabs.js \
648
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -558,10 +558,11 @@
558558
"$(SRCDIR)\forum.js" \
559559
"$(SRCDIR)\fossil.bootstrap.js" \
560560
"$(SRCDIR)\fossil.confirmer.js" \
561561
"$(SRCDIR)\fossil.dom.js" \
562562
"$(SRCDIR)\fossil.fetch.js" \
563
+ "$(SRCDIR)\fossil.numbered-lines.js" \
563564
"$(SRCDIR)\fossil.page.fileedit.js" \
564565
"$(SRCDIR)\fossil.page.forumpost.js" \
565566
"$(SRCDIR)\fossil.page.wikiedit.js" \
566567
"$(SRCDIR)\fossil.storage.js" \
567568
"$(SRCDIR)\fossil.tabs.js" \
@@ -1152,10 +1153,11 @@
11521153
echo "$(SRCDIR)\forum.js" >> $@
11531154
echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
11541155
echo "$(SRCDIR)\fossil.confirmer.js" >> $@
11551156
echo "$(SRCDIR)\fossil.dom.js" >> $@
11561157
echo "$(SRCDIR)\fossil.fetch.js" >> $@
1158
+ echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
11571159
echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
11581160
echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
11591161
echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
11601162
echo "$(SRCDIR)\fossil.storage.js" >> $@
11611163
echo "$(SRCDIR)\fossil.tabs.js" >> $@
11621164
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -558,10 +558,11 @@
558 "$(SRCDIR)\forum.js" \
559 "$(SRCDIR)\fossil.bootstrap.js" \
560 "$(SRCDIR)\fossil.confirmer.js" \
561 "$(SRCDIR)\fossil.dom.js" \
562 "$(SRCDIR)\fossil.fetch.js" \
 
563 "$(SRCDIR)\fossil.page.fileedit.js" \
564 "$(SRCDIR)\fossil.page.forumpost.js" \
565 "$(SRCDIR)\fossil.page.wikiedit.js" \
566 "$(SRCDIR)\fossil.storage.js" \
567 "$(SRCDIR)\fossil.tabs.js" \
@@ -1152,10 +1153,11 @@
1152 echo "$(SRCDIR)\forum.js" >> $@
1153 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1154 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1155 echo "$(SRCDIR)\fossil.dom.js" >> $@
1156 echo "$(SRCDIR)\fossil.fetch.js" >> $@
 
1157 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1158 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1159 echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1160 echo "$(SRCDIR)\fossil.storage.js" >> $@
1161 echo "$(SRCDIR)\fossil.tabs.js" >> $@
1162
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -558,10 +558,11 @@
558 "$(SRCDIR)\forum.js" \
559 "$(SRCDIR)\fossil.bootstrap.js" \
560 "$(SRCDIR)\fossil.confirmer.js" \
561 "$(SRCDIR)\fossil.dom.js" \
562 "$(SRCDIR)\fossil.fetch.js" \
563 "$(SRCDIR)\fossil.numbered-lines.js" \
564 "$(SRCDIR)\fossil.page.fileedit.js" \
565 "$(SRCDIR)\fossil.page.forumpost.js" \
566 "$(SRCDIR)\fossil.page.wikiedit.js" \
567 "$(SRCDIR)\fossil.storage.js" \
568 "$(SRCDIR)\fossil.tabs.js" \
@@ -1152,10 +1153,11 @@
1153 echo "$(SRCDIR)\forum.js" >> $@
1154 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1155 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1156 echo "$(SRCDIR)\fossil.dom.js" >> $@
1157 echo "$(SRCDIR)\fossil.fetch.js" >> $@
1158 echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
1159 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1160 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1161 echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1162 echo "$(SRCDIR)\fossil.storage.js" >> $@
1163 echo "$(SRCDIR)\fossil.tabs.js" >> $@
1164

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button