Oi,
Minha pergunta pode ser um pouco estúpida (desculpas por isso), mas não consigo descobrir como usar um modo personalizado / realçador de sintaxe / preenchimento automático. Alguém pode me ajudar? Eu sou muito novo em brace, ace, e react, mas vi alguns materiais sobre como criar e definir seu modo personalizado usando o Ace. O que não consegui descobrir é como fazer o mesmo com o react-ace.
cristão
Oi,
e qual é a sua implementação? Posso mostrar o que funciona para mim. Não me lembro exatamente, mas acho que tive que instalar também a biblioteca brace
primeiro. Então
npm install -D brace react-ace
E este é meu componente com o editor Ace:
import React from 'react'
import brace from 'brace'
import AceEditor from 'react-ace'
import 'brace/mode/javascript'
import 'brace/theme/tomorrow'
const MyEditor = () => {
return (
<AceEditor
name="my-editor"
mode="javascript"
theme="tomorrow"
value=""
width="100%"
height="500px" />
)
}
export default MyEditor
E aqui está a captura de tela:
Eu poderia usar os modos padrão da chave, de fato. O que me pergunto é como usar meu próprio modo? Eu escrevi um modo personalizado sozinho e quero incluí-lo, mas não fui capaz de fazer isso com o react-ace até agora.
@sichvoge Você fez algum progresso nisso?
Na verdade. No final, desenvolvi meu próprio componente de reação usando Ace e não brace.
É justo - talvez você possa compartilhá-lo quando estiver satisfeito com ele? Obrigado @sichvoge
Claro, eu vou.
@sichvoge , você pode compartilhar seu componente?
Estou tendo o mesmo problema e será muito útil :)
Estou tentando fazer algo semelhante. Importar o modo no front end não parece funcionar para mim.
Parece que o AceEditor está procurando por um arquivo do lado do servidor. Então, acabei simplesmente servindo o arquivo de modo separadamente para meu script empacotado do webpack. (Esta provavelmente não é a maneira certa de fazer isso, mas parece funcionar ....)
Digamos que meu modo personalizado se chame 'eikelang'
Meu código React se parece com isto
import React from 'react';
import AceEditor from 'react-ace';
import 'brace/theme/github';
export default ({value}) => {
<AceEditor
mode="eikelang"
theme="github"
width="auto"
height="200px"
value={value}
/>
};
Eu tenho um arquivo js chamado 'mode-eikelang.js' servido a partir do diretório raiz do meu servidor, que é apenas uma cópia do arquivo do modo mysql brace com alguns nomes alterados:
ace.define('ace/mode/doc_comment_highlight_rules',
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
function(acequire, exports, module) {
'use strict';
let oop = acequire('../lib/oop');
let TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
var DocCommentHighlightRules = function() {
this.$rules = {
'start': [{
token: 'comment.doc.tag',
regex: '@[\\w\\d_]+' // TODO: fix email addresses
},
DocCommentHighlightRules.getTagRule(),
{
defaultToken: 'comment.doc',
caseInsensitive: true
}]
};
};
oop.inherits(DocCommentHighlightRules, TextHighlightRules);
DocCommentHighlightRules.getTagRule = function(start) {
return {
token: 'comment.doc.tag.storage.type',
regex: '\\b(?:TODO|FIXME|XXX|HACK)\\b'
};
};
DocCommentHighlightRules.getStartRule = function(start) {
return {
token: 'comment.doc', // doc comment
regex: '\\/\\*(?=\\*)',
next: start
};
};
DocCommentHighlightRules.getEndRule = function(start) {
return {
token: 'comment.doc', // closing comment
regex: '\\*\\/',
next: start
};
};
exports.DocCommentHighlightRules = DocCommentHighlightRules;
});
ace.define('ace/mode/eikelang_highlight_rules', ['require', 'exports', 'module', 'ace/lib/oop', 'ace/lib/lang', 'ace/mode/doc_comment_highlight_rules', 'ace/mode/text_highlight_rules'], function(acequire, exports, module) {
let oop = acequire('../lib/oop');
let lang = acequire('../lib/lang');
let DocCommentHighlightRules = acequire('./doc_comment_highlight_rules').DocCommentHighlightRules;
let TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
let EikelangHighlightRules = function() {
let builtins = 'drop|hash|keep|linear_transformation|map|rename|string_manipulation|string_submatcher';
let keywordMapper = this.createKeywordMapper({
'support.function': builtins
}, 'identifier', true);
function string(rule) {
let start = rule.start;
let escapeSeq = rule.escape;
return {
token: 'string.start',
regex: start,
next: [
{token: 'constant.language.escape', regex: escapeSeq},
{token: 'string.end', next: 'start', regex: start},
{defaultToken: 'string'}
]
};
}
this.$rules = {
'start': [{
token: 'comment', regex: '(?:-- |#).*$'
},
string({start: '"', escape: /\\[0'"bnrtZ\\%_]?/}),
string({start: '\'', escape: /\\[0'"bnrtZ\\%_]?/}),
DocCommentHighlightRules.getStartRule('doc-start'),
{
token: 'comment', // multi line comment
regex: /\/\*/,
next: 'comment'
}, {
token: 'constant.numeric', // hex
regex: /0[xX][0-9a-fA-F]+|[xX]'[0-9a-fA-F]+'|0[bB][01]+|[bB]'[01]+'/
}, {
token: 'constant.numeric', // float
regex: '[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b'
}, {
token: keywordMapper,
regex: '[a-zA-Z_$][a-zA-Z0-9_$]*\\b'
}, {
token: 'constant.class',
regex: '@@?[a-zA-Z_$][a-zA-Z0-9_$]*\\b'
}, {
token: 'constant.buildin',
regex: '`[^`]*`'
}, {
token: 'keyword.operator',
regex: '\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|='
}, {
token: 'paren.lparen',
regex: '[\\(]'
}, {
token: 'paren.rparen',
regex: '[\\)]'
}, {
token: 'text',
regex: '\\s+'
}],
'comment': [
{token: 'comment', regex: '\\*\\/', next: 'start'},
{defaultToken: 'comment'}
]
};
this.embedRules(DocCommentHighlightRules, 'doc-', [DocCommentHighlightRules.getEndRule('start')]);
this.normalizeRules();
};
oop.inherits(EikelangHighlightRules, TextHighlightRules);
exports.EikelangHighlightRules = EikelangHighlightRules;
});
ace.define('ace/mode/eikelang', ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/eikelang_highlight_rules'],
function(acequire, exports, module) {
let oop = acequire('../lib/oop');
let TextMode = acequire('../mode/text').Mode;
let EikelangHighlightRules = acequire('./eikelang_highlight_rules').EikelangHighlightRules;
let Mode = function() {
this.HighlightRules = EikelangHighlightRules;
this.$behaviour = this.$defaultBehaviour;
};
oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = ['--', '#']; // todo space
this.blockComment = {start: '/*', end: '*/'};
this.$id = 'ace/mode/eikelang';
}).call(Mode.prototype);
exports.Mode = Mode;
});
Olá @ pollen8 ,
Se você der uma olhada no código react-ace, você verá que o componente tenta definir o modo usando seu nome
O que significa que você tem que ter certeza que seu modo já está no cache "Ace" usando ace.define
e oop.inherits(Mode, TextMode)
e outro código Ace nativo, que eu acho muito antigo quando você tem ES6 do seu lado.
Então, por que não escrever seu modo personalizado simplesmente como escrevemos qualquer outra classe?
Isso faria com que sua classe de modo personalizado parecesse muito melhor
(menos linhas de código + melhor sintaxe => menos manutenção)
Então eu:
componentDidMount
e chamei session.setMode
com uma instância do meu modo personalizado.Meu modo personalizado é:
export default class CustomSqlMode extends ace.acequire('ace/mode/text').Mode {
constructor(){
super();
// Your code goes here
}
}
E meu código react-ace se parece com:
render() {
return <div>
<AceEditor
ref="aceEditor"
mode="sql" // Default value since this props must be set.
theme="chrome" // Default value since this props must be set.
/>
</div>;
}
componentDidMount() {
const customMode = new CustomSqlMode();
this.refs.aceEditor.editor.getSession().setMode(customMode);
}
A única desvantagem que ele vê é depender de ace.acequire('ace/mode/text').Mode
para ser uma linha válida quando eu defino a classe de modo.
Mas é válido de qualquer maneira, pois react-ace coloca o módulo "ace" em window.ace (https://github.com/ajaxorg/ace/blob/4c7e5eb3f5d5ca9434847be51834a4e41661b852/lib/ace/worker/worker.js#L19)
@AlonBe @
Alguém tem um jsfiddle ou exemplo de trabalho para isso?
Tentei seguir as instruções que @AlonBe listou com o modo personalizado fornecido por @ pollen8 e, infelizmente, não consigo fazer com que o realce de sintaxe seja registrado corretamente ... :(
Qualquer ajuda seria apreciada.
Onde meu editor está sendo renderizado:
componentDidMount () {
const customMode = new CustomSqlMode();
this.refs.ace.editor.getSession().setMode(test);
console.log(customMode);
}
@solemnify , Você tentou fazer this.refs.ace.editor.getSession().setMode(customMode);
?
Tente seguir a classe CustomSqlMode que criei.
Para ver se funciona, você pode colocar dentro do construtor a seguinte linha:
this.lineCommentStart = '--';
Se você quiser usar o realce de sintaxe, você precisa substituir this.HighlightRules
da classe de modo personalizado.
Dê uma olhada em um dos modos atuais, como sql_mode
@AlonBe
Você poderia fornecer um exemplo de código para colocar em seu componente CustomSqlMode?
Não sei como transformar as regras de destaque em es6 ...
Agradeço antecipadamente por sua ajuda.
O código a seguir funcionou para mim:
App.js
import React, { Component } from 'react';
import brace from 'brace';
import AceEditor from 'react-ace';
import CustomSqlMode from './CustomSqlMode.js'
import 'brace/theme/github';
class App extends Component {
componentDidMount() {
const customMode = new CustomSqlMode();
this.refs.aceEditor.editor.getSession().setMode(customMode);
}
render() {
return (
<div className="App">
<AceEditor
ref="aceEditor"
mode="text"
theme="github"
name="UNIQUE_ID_OF_DIV"
editorProps={{ $blockScrolling: true }}
/>
</div>
);
}
}
export default App;
CustomSqlMode.js
import 'brace/mode/java';
export class CustomHighlightRules extends window.ace.acequire("ace/mode/text_highlight_rules").TextHighlightRules {
constructor() {
super();
this.$rules = {
"start": [{
token: "comment",
regex: "#.*$"
}, {
token: "string",
regex: '".*?"'
}]
};
}
}
export default class CustomSqlMode extends window.ace.acequire('ace/mode/java').Mode {
constructor() {
super();
this.HighlightRules = CustomHighlightRules;
}
}
O código anterior destaca apenas os comentários e strings. Não tenho certeza se o que fiz foi uma boa prática ou não, mas pelo menos funciona.
@ newint33h obrigado! Funciona para mim.
@ newint33h Tentei usar essa estrutura, mas ela reclama que TypeError: Não é possível ler a propriedade 'editor' de undefined.
@shuotongli Eu tive o mesmo problema e parece que o problema é porque o this.refs
do React agora está obsoleto. Existem algumas maneiras de criar um ref, dependendo da versão do React que você está usando. Para a forma atualmente suportada, verifique isto:
https://reactjs.org/docs/refs-and-the-dom.html#creating -refs
O código a seguir funcionou para mim:
App.js
import React, { Component } from 'react'; import brace from 'brace'; import AceEditor from 'react-ace'; import CustomSqlMode from './CustomSqlMode.js' import 'brace/theme/github'; class App extends Component { componentDidMount() { const customMode = new CustomSqlMode(); this.refs.aceEditor.editor.getSession().setMode(customMode); } render() { return ( <div className="App"> <AceEditor ref="aceEditor" mode="text" theme="github" name="UNIQUE_ID_OF_DIV" editorProps={{ $blockScrolling: true }} /> </div> ); } } export default App;
CustomSqlMode.js
import 'brace/mode/java'; export class CustomHighlightRules extends window.ace.acequire("ace/mode/text_highlight_rules").TextHighlightRules { constructor() { super(); this.$rules = { "start": [{ token: "comment", regex: "#.*$" }, { token: "string", regex: '".*?"' }] }; } } export default class CustomSqlMode extends window.ace.acequire('ace/mode/java').Mode { constructor() { super(); this.HighlightRules = CustomHighlightRules; } }
O código anterior destaca apenas os comentários e strings. Não tenho certeza se o que fiz foi uma boa prática ou não, mas pelo menos funciona.
porque o modo = 'texto', o que significa texto?
@TaurusWood , como o primeiro render
ocorre antes de componentDidMount
- você deve passar um "modo" válido para o componente react-ace.
mais tarde, em componentDidMount
você pode ver que o código substitui esse modo ( setMode
)
e BTW, se eu não estou entendendo errado, mode = 'text' é o modo básico do Ace que todos os outros estão substituindo
Alguém pode explicar por que não está mais funcionando, todos os meus códigos são interpretados como um texto em vez de um arquivo java depois de definir um modo personalizado? Obrigado
O código a seguir funcionou para mim:
App.js
import React, { Component } from 'react'; import brace from 'brace'; import AceEditor from 'react-ace'; import CustomSqlMode from './CustomSqlMode.js' import 'brace/theme/github'; class App extends Component { componentDidMount() { const customMode = new CustomSqlMode(); this.refs.aceEditor.editor.getSession().setMode(customMode); } render() { return ( <div className="App"> <AceEditor ref="aceEditor" mode="text" theme="github" name="UNIQUE_ID_OF_DIV" editorProps={{ $blockScrolling: true }} /> </div> ); } } export default App;
CustomSqlMode.js
import 'brace/mode/java'; export class CustomHighlightRules extends window.ace.acequire("ace/mode/text_highlight_rules").TextHighlightRules { constructor() { super(); this.$rules = { "start": [{ token: "comment", regex: "#.*$" }, { token: "string", regex: '".*?"' }] }; } } export default class CustomSqlMode extends window.ace.acequire('ace/mode/java').Mode { constructor() { super(); this.HighlightRules = CustomHighlightRules; } }
O código anterior destaca apenas os comentários e strings. Não tenho certeza se o que fiz foi uma boa prática ou não, mas pelo menos funciona.
Comentários muito úteis
O código a seguir funcionou para mim:
App.js
CustomSqlMode.js
O código anterior destaca apenas os comentários e strings. Não tenho certeza se o que fiz foi uma boa prática ou não, mas pelo menos funciona.