use crate::common::editor_runtime::{
AccessibilityRole, CaretPolicy, ClipboardPolicy, CommandFilter, EditorCommand, PolicyBundle,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodeCommand {
InsertChar,
InsertNewline,
DeletePrev,
DeleteNext,
DeleteWordLeft,
DeleteWordRight,
IndentLines,
DedentLines,
ToggleLineComment,
DuplicateSelection,
MoveLineUp,
MoveLineDown,
AddCaretAbove,
AddCaretBelow,
ClearExtraCarets,
Undo,
Redo,
MoveLeft,
MoveRight,
MoveUp,
MoveDown,
MoveWordLeft,
MoveWordRight,
MoveLineStart,
MoveLineEnd,
MoveDocStart,
MoveDocEnd,
PageUp,
PageDown,
SelectLeft,
SelectRight,
SelectUp,
SelectDown,
SelectWordLeft,
SelectWordRight,
SelectLineStart,
SelectLineEnd,
SelectDocStart,
SelectDocEnd,
SelectAll,
Copy,
Cut,
Paste,
}
impl EditorCommand for CodeCommand {
fn is_regressive(&self) -> bool {
matches!(
self,
Self::DeletePrev
| Self::DeleteNext
| Self::DeleteWordLeft
| Self::DeleteWordRight
| Self::Cut
| Self::Undo
| Self::Redo
| Self::MoveLineUp
| Self::MoveLineDown
)
}
fn mutates_document(&self) -> bool {
matches!(
self,
Self::InsertChar
| Self::InsertNewline
| Self::DeletePrev
| Self::DeleteNext
| Self::DeleteWordLeft
| Self::DeleteWordRight
| Self::IndentLines
| Self::DedentLines
| Self::ToggleLineComment
| Self::DuplicateSelection
| Self::MoveLineUp
| Self::MoveLineDown
| Self::Undo
| Self::Redo
| Self::Cut
| Self::Paste
)
}
}
pub const CODE_EDITOR_PRESET: PolicyBundle = PolicyBundle {
command_filter: CommandFilter::All,
caret_policy: CaretPolicy::Blinking,
access_role: AccessibilityRole::Editor,
clipboard_policy: ClipboardPolicy::Full,
};
pub const CODE_READ_ONLY_PRESET: PolicyBundle = PolicyBundle {
command_filter: CommandFilter::ReadOnly,
caret_policy: CaretPolicy::Hidden,
access_role: AccessibilityRole::Document,
clipboard_policy: ClipboardPolicy::CopyAndSelectAllOnly,
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_only_rejects_every_code_mutation() {
let f = CommandFilter::ReadOnly;
for cmd in [
CodeCommand::InsertChar,
CodeCommand::InsertNewline,
CodeCommand::DeletePrev,
CodeCommand::IndentLines,
CodeCommand::DedentLines,
CodeCommand::ToggleLineComment,
CodeCommand::DuplicateSelection,
CodeCommand::MoveLineUp,
CodeCommand::MoveLineDown,
CodeCommand::Undo,
CodeCommand::Redo,
CodeCommand::Cut,
CodeCommand::Paste,
] {
assert!(!f.accepts(cmd), "read-only must reject {cmd:?}");
}
}
#[test]
fn read_only_still_navigates_selects_and_copies() {
let f = CommandFilter::ReadOnly;
for cmd in [
CodeCommand::MoveLeft,
CodeCommand::MoveLineStart,
CodeCommand::PageDown,
CodeCommand::SelectWordRight,
CodeCommand::SelectAll,
CodeCommand::Copy,
] {
assert!(f.accepts(cmd), "read-only must accept {cmd:?}");
}
}
#[test]
fn caret_management_is_not_a_mutation() {
let f = CommandFilter::ReadOnly;
assert!(f.accepts(CodeCommand::AddCaretAbove));
assert!(f.accepts(CodeCommand::AddCaretBelow));
assert!(f.accepts(CodeCommand::ClearExtraCarets));
}
#[test]
fn editor_preset_accepts_everything() {
let f = CommandFilter::All;
for cmd in [
CodeCommand::InsertChar,
CodeCommand::ToggleLineComment,
CodeCommand::Paste,
CodeCommand::MoveLeft,
] {
assert!(f.accepts(cmd));
}
}
#[test]
fn presets_report_read_only_correctly() {
assert!(!CODE_EDITOR_PRESET.is_read_only());
assert!(CODE_READ_ONLY_PRESET.is_read_only());
}
#[test]
fn read_only_preset_uses_a_text_range_capable_role() {
assert_eq!(
CODE_READ_ONLY_PRESET.access_role,
AccessibilityRole::Document
);
}
}