New and Save¶
本节添加新建和保存文件的功能。
首先,在EditorEdit
消息处理中检查是否对文件进行了修改,并且记录文件的修改状态。
struct Editor {
// ...
modified: bool
}
// ... In `update` function
Message::EditorEdit(action) => {
match &action {
text_editor::Action::Edit(_) => self.modified = true,
_ => {}
}
self.content.edit(action);
Command::none()
},
Message::FileOpened(Ok((path, result))) => {
self.path = Some(path);
self.modified = false;
self.content = text_editor::Content::with(&result);
Command::none()
},
// ...
Message::OpenButtonPressed => {
self.modified = false;
Command::perform(pick_file(), Message::FileOpened)
},
其次,调整文件路径控件的不同显示状态:
- 当文件路径为空时,为新文件,显示“New File”。
- 当打开一个文件时,显示文件路径。
- 当文件被修改后,文件路径后加上“*”。
- 当打开文件出错时,显示错误信息。
let path_indicator = if let Some(error) = &self.error {
match error {
Error::DialogClosed => text("Dialog closed"),
Error::IO(kind) => text(format!("I/O error: {:?}", kind))
}
} else {
let path_text = match &self.path {
None => String::from("New file"),
Some(path) => path.to_string_lossy().to_string()
};
let suffix = if self.modified { "*" } else { "" };
text(format!("{}{}", path_text, suffix))
};
在创建文件时,需要清空文件路径和内容,以及清空错误信息。加入一个新的消息类型NewButtonPressed
,由一个按钮触发,在update
函数中执行这个逻辑。
enum Message {
EditorEdit(text_editor::Action),
FileOpened(Result<(PathBuf, Arc<String>), Error>),
NewButtonPressed,
OpenButtonPressed
}
// ... In `view` function
let controls = row![
button("New").on_press(Message::NewButtonPressed),
button("Open").on_press(Message::OpenButtonPressed)
];
// ... In matching logic in `update` function
Message::NewButtonPressed => {
self.content = text_editor::Content::new();
self.error = None;
self.path = None;
self.modified = false;
Command::none()
},
// ...
接下来处理保存文件的逻辑,当存在文件路径时,保存文件,否则打开文件选择对话框。
async fn save_file(path: Option<PathBuf>, content: String) -> Result<PathBuf, Error> {
let path = if let Some(path) = path {
path
} else {
rfd::AsyncFileDialog::new()
.set_title("Save the file to...")
.save_file()
.await
.ok_or(Error::DialogClosed)?
.path()
.to_path_buf()
};
tokio::fs::write(&path, content)
.await
.map_err(|err| err.kind())
.map_err(Error::IO)
.map(|_| path)
}
在保存文件时,需要
- 检查文件的修改状态,如果文件没有修改,不执行保存操作。
- 检查文件路径是否为空,如果为空,打开文件选择对话框,否则直接保存文件。
- 加入一个新的消息类型
SaveButtonPressed
,由一个按钮触发,在update
函数中执行这个逻辑。
enum Message {
EditorEdit(text_editor::Action),
FileOpened(Result<(PathBuf, Arc<String>), Error>),
FileSaved(Result<PathBuf, Error>),
NewButtonPressed,
OpenButtonPressed,
SaveButtonPressed
}
// ... In `view` function
let controls = row![
button("New").on_press(Message::NewButtonPressed),
button("Open").on_press(Message::OpenButtonPressed),
button("Save").on_press(Message::SaveButtonPressed)
];
// ... In matching logic in `update` function
Message::FileSaved(Ok(path)) => {
self.path = Some(path);
self.modified = false;
Command::none()
},
Message::FileOpened(Err(error)) | Message::FileSaved(Err(error)) => {
self.error = Some(error);
Command::none()
},
// ...
Message::SaveButtonPressed => {
let content = self.content.text();
match self.modified {
false => Command::none(),
true => Command::perform(
save_file(self.path.clone(), content),
Message::FileSaved
)
}
}
最后,调整三个按钮之间的间距
let controls = row![
button("New").on_press(Message::NewButtonPressed),
button("Open").on_press(Message::OpenButtonPressed),
button("Save").on_press(Message::SaveButtonPressed)
].spacing(10);
以下为完整的main.rs
文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
|