diff --git a/parser/CodeBlockNode.php b/parser/CodeBlockNode.php index e03d2760..a40ec636 100644 --- a/parser/CodeBlockNode.php +++ b/parser/CodeBlockNode.php @@ -25,6 +25,64 @@ public function toSyntax() if (!empty($this->data['attrs']['data-filename'])) { $openingTag .= ' ' . $this->data['attrs']['data-filename']; } + $extraTag = ''; + if (isset($this->data['attrs']['data-sln-old'])) + { + $sln_old = $this->data['attrs']['data-sln-old']; + if (is_numeric($sln_old)) + { + $sln_old = (int) $sln_old; + } + else + { + $sln_old = 1; + } + } + if (isset($this->data['attrs']['data-sln'])) + { + $start_line_numbers_at = $this->data['attrs']['data-sln']; + if (is_numeric($start_line_numbers_at)) + { + $start_line_numbers_at = (int) $start_line_numbers_at; + if ($start_line_numbers_at > 0) + $extraTag .= 'enable_line_numbers="true", '; + else + $extraTag .= 'enable_line_numbers="false", '; + $extraTag .= 'start_line_numbers_at="' . abs($start_line_numbers_at) .'"'; + } + else + { + $extraTag = 'enable_line_numbers="false"'; + } + } + if (isset($this->data['attrs']['data-hle'])) + { + $highlight_lines_extra = $this->data['attrs']['data-hle']; + $arr = explode(',', $highlight_lines_extra); + $str = ''; + foreach($arr as $val) + { + if ($str) $str .= ','; + if (is_numeric($val)) + { + $ival = (int) $val; + if ($sln_old > 0 && $ival > 0) + $str .= $ival - $sln_old + 1; + else + $str .= abs($ival); + } + } + if ($str) + { + if (!$extraTag) + $extraTag = '['; + else + $extraTag .= ', '; + $extraTag .= 'highlight_lines_extra="' . $str . '"'; + } + } + if ($extraTag) $openingTag .= ' [' . $extraTag . ']'; + $openingTag .= '>'; return $openingTag . "\n" . $this->data['content'][0]['text'] . "\n"; } diff --git a/renderer.php b/renderer.php index da6cbfc3..c0e0ecac 100644 --- a/renderer.php +++ b/renderer.php @@ -335,13 +335,42 @@ public function preformatted($text) $this->nodestack->drop('preformatted'); } - public function code($text, $lang = null, $file = null) + public function code($text, $lang = null, $file = null, $ext = null) { $this->clearBlock(); $node = new Node('code_block'); $node->attr('class', 'code ' . $lang); $node->attr('data-language', $lang); - $node->attr('data-filename', $file); + $node->attr('data-filename', rtrim($file)); + if ($ext) + { + if (isset($ext['start_line_numbers_at'])) + { + $start_line_numbers_at = $ext['start_line_numbers_at']; + if (isset($ext['enable_line_numbers']) && ($ext['enable_line_numbers'] === false)) + { + $start_line_numbers_at = -$start_line_numbers_at; + } + $node->attr('data-sln', $start_line_numbers_at); + $node->attr('data-sln-old', $start_line_numbers_at); + } + else + { + $node->attr('data-sln-old', '1'); + } + if (isset($ext['highlight_lines_extra'])) + { + $str = ''; + asort($ext['highlight_lines_extra']); + foreach($ext['highlight_lines_extra'] as $hle) + { + if ($str) $str .= ','; + if ($start_line_numbers_at > 0) $hle += $start_line_numbers_at - 1; + $str .= $hle; + } + $node->attr('data-hle', $str); + } + } $this->nodestack->addTop($node); $this->cdata(trim($text, "\n")); $this->nodestack->drop('code_block'); diff --git a/script/nodeviews/CodeView.js b/script/nodeviews/CodeView.js index e6aadb02..9fc86d94 100644 --- a/script/nodeviews/CodeView.js +++ b/script/nodeviews/CodeView.js @@ -22,7 +22,20 @@ class CodeView extends AbstractNodeView { .on('keydown', this.constructor.preventSubmit) .on('blur', this.dispatchMetaUpdate.bind(this)) .attr('list', 'codelanguages'); + this.$sln = jQuery('') + .prop('placeholder', 'start line num at') + .prop('size', '12') + .on('keydown', this.constructor.preventSubmit) + .on('blur', this.dispatchMetaUpdate.bind(this)); + this.$slno = jQuery('') + .prop('type', 'hidden'); + this.$hle = jQuery('') + .prop('placeholder', 'highlight lines extra') + .prop('size', '40') + .on('keydown', this.constructor.preventSubmit) + .on('blur', this.dispatchMetaUpdate.bind(this)); this.$title.append(this.$fn).append(this.$lang); + this.$title.append(this.$sln).append(this.$slno).append(this.$hle); this.$fileDom.append(this.$title); this.$contentWrapper = jQuery('
'); this.$fileDom.append(this.$contentWrapper); @@ -34,6 +47,9 @@ class CodeView extends AbstractNodeView { this.$fn.val(attrs['data-filename']); this.$lang.val(attrs['data-language']); + this.$sln.val(attrs['data-sln']); + this.$slno.val(attrs['data-sln-old']); + this.$hle.val(attrs['data-hle']); Object.entries(attrs).forEach(([key, value]) => this.dom.setAttribute(key, value)); } @@ -48,6 +64,9 @@ class CodeView extends AbstractNodeView { const newAttrs = { 'data-filename': this.$fn.val(), 'data-language': this.$lang.val(), + 'data-sln': this.$sln.val(), + 'data-sln-old': this.$slno.val(), + 'data-hle': this.$hle.val(), }; const nodeStartPos = this.getPos(); this.outerView.dispatch(this.outerView.state.tr.setNodeMarkup( diff --git a/script/schema.js b/script/schema.js index 60947f44..86a8d97b 100644 --- a/script/schema.js +++ b/script/schema.js @@ -78,6 +78,9 @@ export default function getSpec() { class: { default: 'code' }, 'data-filename': { default: '' }, 'data-language': { default: '' }, + 'data-sln': { default: '' }, + 'data-sln-old': { default: '' }, + 'data-hle': { default: '' }, }; codeBlock.toDOM = function toDOM(node) { return ['pre', node.attrs, 0];