Open ghost opened 6 years ago
The "highlight" term in cursive is used to describe selected items like buttons, that appear with inverted colors (background and foreground colors swap).
"Highlight" as in "syntax highlighting" is about giving different colors or effects to parts of the text. This is only recently supported (not even published yet to crates.io), and is currently only supported for TextView
that display fixed content, not for an editable TextArea
.
Here is how this works currently:
StyledString
: it defines a text and how it should be "styled".TextView
(or other view) prints its StyledString
accorging to instructions.So if you want to have an editor with syntax highlighting, you will need:
TextArea
that may "style" its content. I haven't though about it much yet, but it may end up in the official TextArea
.I know this is a really old issue, but for those who find this issue in the future as I did, the way I solved this was somewhat similar to what @gyscos suggested, so I'm leaving it here in case it might inspire others. This is pretty hacky, so any suggestions are appreciated:
let mut new_message = message.clone();
if templated_words.len() > 0 {
for word in templated_words.iter() {
let re_matcher = format!(r#"({})"#, word.clone());
let re = Regex::new(re_matcher.as_str()).unwrap();
for capture in re.captures_iter(new_message.clone().as_str()) {
// I'm implementing a simple templating for highlighting words but matching
// highlighted words separated by spaces was something I didn't know how to do
// so I replace the spaces with underscores first, so I'm only looking for "one" word
let plain_word = capture.get(1).unwrap().as_str().replace(" ", "_");
let start = capture.get(1).unwrap().start();
let end = capture.get(1).unwrap().end();
new_message = new_message.clone()[..start].to_string()
+ &plain_word[..]
+ &new_message.clone()[end..];
}
}
let styled_room_text = new_message
.lines()
.map(|sentence| {
let styled_sentence = sentence
.split(' ')
.map(|word| {
// now I can split that templated word above and join with a space again, so I'm working with
// one string that might have spaces in it
let trimmed_word = &word.split("_").collect::<Vec<&str>>().join(" ");
let sanitized_word: String;
// this part here is so that I could still highlight a word if it was next to a punctuation mark.
// this is a very brittle and naive implementation that works for my project but I can't recommend it.
let last_char = if trimmed_word.len() > 0 {
trimmed_word.clone().chars().last().unwrap()
} else {
' '
};
if last_char == '.'
|| last_char == '!'
|| last_char == '?'
|| last_char == ','
{
sanitized_word = trimmed_word[..trimmed_word.len() - 1].to_string();
} else {
sanitized_word = trimmed_word.to_string();
}
// templated_words is a Vec<String> that might contain strings with spaces in them so that's why the work
// above with splitting and replacing is needed
if templated_words.contains(&sanitized_word) {
let mut styled_word = SpannedString::styled(
sanitized_word,
Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
);
// we highlight the word above, and then append the corresponding punctuation as a plain string
if last_char == '.' {
styled_word.append(".");
}
if last_char == '!' {
styled_word.append("!");
}
if last_char == '?' {
styled_word.append("?");
}
if last_char == ',' {
styled_word.append(",");
}
styled_word.append_plain(" ");
styled_word
} else {
let mut plain_word = SpannedString::styled(
word.to_string(),
Style::from(Color::Dark(BaseColor::Green)),
);
plain_word.append_plain(" ");
plain_word
}
})
.reduce(|mut acc, word| {
acc.append(word);
acc
})
.unwrap();
styled_sentence
})
.fold(StyledString::new(), |mut s, l| {
s.append(l);
s.append_plain("\n");
s
});
styled_room_text
} else {
SpannedString::styled(message, Style::from(Color::Dark(BaseColor::Green)))
}
I hope this can help others too.
Note that since then, cursive-syntect
was added to simplify using syntect to generate a StyledString
.
Question
I want add to my text redactor rust code syntax highlight, how i can do this?