Skip to content

Commit a9f4732

Browse files
committed
Merge pull request GitbookIO#356 from GitbookIO/feature/includes
Support importing code snippets
2 parents 5200454 + d16577e commit a9f4732

File tree

6 files changed

+115
-4
lines changed

6 files changed

+115
-4
lines changed

lib/parse/code_include.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var fs = require('fs');
2+
var path = require('path');
3+
4+
module.exports = function(code, folder) {
5+
folder = folder || '';
6+
7+
return code.replace(/{{([\s\S]+?)}}/g, function(match, filename) {
8+
// Normalize filename
9+
var fname = path.join(folder, filename.trim());
10+
11+
// Try including snippet from FS
12+
try {
13+
// Trim trailing newlines/space of imported snippets
14+
return fs.readFileSync(fname, 'utf8').trimRight();
15+
} catch(err) {}
16+
17+
// If fails leave content as is
18+
return match;
19+
});
20+
};

lib/parse/page.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var hljs = require('highlight.js');
55
var lex = require('./lex');
66
var renderer = require('./renderer');
77

8+
var codeInclude = require('./code_include');
89
var lnormalize = require('../utils/lang').normalize;
910

1011

@@ -74,15 +75,20 @@ function parsePage(src, options) {
7475
// Main language
7576
var lang = validLangs ? langs[0] : null;
7677

78+
// codeInclude shortcut
79+
var ci = function(code) {
80+
return codeInclude(code, options.dir);
81+
};
82+
7783
return {
7884
id: section.id,
7985
type: section.type,
8086
content: render(nonCodeNodes),
8187
lang: lang,
8288
code: {
83-
base: codeNodes[0].text,
84-
solution: codeNodes[1].text,
85-
validation: codeNodes[2].text,
89+
base: ci(codeNodes[0].text),
90+
solution: ci(codeNodes[1].text),
91+
validation: ci(codeNodes[2].text),
8692
// Context is optional
8793
context: codeNodes[3] ? codeNodes[3].text : null,
8894
}

lib/parse/renderer.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var url = require('url');
22
var inherits = require('util').inherits;
33
var links = require('../utils').links;
4+
var codeInclude = require('./code_include');
45

56

67
var path = require('path');
@@ -125,7 +126,7 @@ GitBookRenderer.prototype._createCheckboxAndRadios = function(text) {
125126
var length = splittedText.length;
126127
var label = '<label class="quiz-label" for="' + quizIdentifier + '">' + splittedText[length - 1] + '</label>';
127128
return text.replace(fieldRegex, field).replace(splittedText[length - 1], label);
128-
}
129+
};
129130

130131
GitBookRenderer.prototype.tablecell = function(content, flags) {
131132
return GitBookRenderer.super_.prototype.tablecell(this._createCheckboxAndRadios(content), flags);
@@ -135,5 +136,15 @@ GitBookRenderer.prototype.listitem = function(text) {
135136
return GitBookRenderer.super_.prototype.listitem(this._createCheckboxAndRadios(text));
136137
};
137138

139+
GitBookRenderer.prototype.code = function(code, lang, escaped) {
140+
return GitBookRenderer.super_.prototype.code.call(
141+
this,
142+
// Import code snippets
143+
codeInclude(code, this._extra_options.dir),
144+
lang,
145+
escaped
146+
);
147+
};
148+
138149
// Exports
139150
module.exports = GitBookRenderer;

test/fixtures/INCLUDES.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Beautiful chapter
2+
3+
Here is a nice included snippet :
4+
5+
```c
6+
{{ included.c }}
7+
```
8+
9+
----
10+
11+
An exercise using includes
12+
13+
```c
14+
{{ included.c }}
15+
16+
Remove this extra code at the end
17+
```
18+
19+
```c
20+
{{ included.c }}
21+
```
22+
23+
```c
24+
{{ included.c }}
25+
26+
This validation code is wrong but who cares ?
27+
```
28+
29+
----

test/fixtures/included.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdio.h>
2+
3+
int main(int argc, char *argv[]) {
4+
printf("All is well\n");
5+
6+
return 0;
7+
}

test/includes.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var fs = require('fs');
2+
var path = require('path');
3+
var assert = require('assert');
4+
5+
var page = require('../').parse.page;
6+
7+
var FIXTURES_DIR = path.join(__dirname, './fixtures/');
8+
9+
function loadPage (name, options) {
10+
var CONTENT = fs.readFileSync(FIXTURES_DIR + name + '.md', 'utf8');
11+
return page(CONTENT, options);
12+
}
13+
14+
15+
describe('Code includes', function() {
16+
17+
var LEXED = loadPage('INCLUDES', {
18+
'dir': FIXTURES_DIR,
19+
});
20+
21+
var INCLUDED_C = fs.readFileSync(path.join(FIXTURES_DIR, 'included.c'), 'utf8');
22+
23+
it('should work for snippets', function() {
24+
assert.equal(LEXED[0].type, 'normal');
25+
// Has replaced include
26+
assert.equal(
27+
LEXED[0].content.indexOf('{{ included.c }}'),
28+
-1
29+
);
30+
});
31+
32+
it('should work for exercises', function() {
33+
assert.equal(LEXED[1].type, 'exercise');
34+
35+
// Solution is trimmed version of source
36+
assert.equal(LEXED[1].code.solution, INCLUDED_C.trim());
37+
});
38+
});

0 commit comments

Comments
 (0)