Compare commits

..

32 commits

Author SHA1 Message Date
834554167e chore: fige Cargo.lock (epoch-1.10.0, [patch] locaux)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:02:21 +02:00
79f6777d08 merge: epoch-1.10.0 d'upstream
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:00:05 +02:00
Michael Murphy
5ddf511599
i18n: translation update from Hosted Weblate (#631)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for [Pop OS/COSMIC
Edit](https://hosted.weblate.org/projects/pop-os/cosmic-edit/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/pop-os/cosmic-edit/matrix-auto.svg)
2026-10-06 21:55:46 +02:00
Michael Aaron Murphy
35b6a05bc1 Epoch 1.10.0 version update
[x] Generated by cosmic-epoch scripts/version-update.sh
2026-10-06 21:55:24 +02:00
Hojjat
1398716508 chore: clean up formatting and lint 2026-09-30 13:41:31 -06:00
Hojjat
d7b82fad91 chore: set up github actions for fmt, test, and clippy 2026-09-30 13:41:31 -06:00
Kartik
690065d9a8
Add license url & update developers name to System76 (#635)
- [X] I have disclosed use of any AI generated code in my commit
messages.
- If you are using an LLM, and do not fully understand the changes it is
making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex
code that lacks enough context for a proper fix or feature inclusion.
This results in considerably longer code reviews. Due to this, AI
authored or partially authored PRs may be closed without comment.
- [X] I understand these changes in full and will be able to respond to
review comments.
- [X] My change is accurately described in the commit message.
- [X] My contribution is tested and working as described.
- [X] I have read the [Developer Certificate of
Origin](https://developercertificate.org/) and certify my contribution
under its conditions.
2026-09-30 13:29:08 -06:00
Jeremy Soller
7baa24b649 COSMIC policy update
Generated by cosmic-epoch scripts/policy-update.sh. Uses `policy_nobuild` branch to avoid package builds as it contains no code changes.
2026-09-30 09:55:31 -06:00
936e57b63e chore: fige Cargo.lock (epoch-1.9.0, [patch] locaux)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 21:03:54 +02:00
c45b23aa85 merge: epoch-1.9.0 d'upstream
# Conflicts:
#	Cargo.lock
2026-09-24 20:50:47 +02:00
Hojjat
bfc98bf219 chore: update libcosmic to fix esc, and bindings in context menu 2026-09-23 11:30:54 -06:00
Hosted Weblate
4b38bdf398
i18n: translation updates from weblate
Co-authored-by: therealmate <hellogaming91@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/hu/
Translation: Pop OS/COSMIC Edit
2026-09-19 10:51:35 +02:00
Michael Aaron Murphy
14aba66228 chore: update debian/rules 2026-09-16 16:28:59 -04:00
Michael Aaron Murphy
430120f6ff chore: update cosmic-files and libcosmic 2026-09-16 16:28:59 -04:00
Hojjat
9307793661 feat: use libcosmic's context_menu widget 2026-09-16 16:28:59 -04:00
Hojjat
505ecd18fe chore: adopt typed surface actions from libcosmic 2026-09-16 16:28:59 -04:00
Michael Aaron Murphy
4b4871ecf4 Epoch 1.9.0 version update
Generated by cosmic-epoch scripts/version-update.sh
2026-09-16 16:28:59 -04:00
Michael Murphy
1054b6a7fd
i18n: translation update from Hosted Weblate (#616)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for [Pop OS/COSMIC
Edit](https://hosted.weblate.org/projects/pop-os/cosmic-edit/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/pop-os/cosmic-edit/matrix-auto.svg)
2026-09-15 21:56:46 +02:00
Hosted Weblate
139cfaaf5c
i18n: translation updates from weblate
Co-authored-by: Amadɣas <massiin@proton.me>
Co-authored-by: Blauen <butterflee555@gmail.com>
Co-authored-by: CYAXXX <85353920+CYAXXX@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kurt Harren Catindig <kurtharrencatindig03@gmail.com>
Co-authored-by: Quentin PAGÈS <quentinantonin@free.fr>
Co-authored-by: Satakun Utama <galaxytomostore@gmail.com>
Co-authored-by: VandaL <vandalhj@gmail.com>
Co-authored-by: therealmate <hellogaming91@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/hu/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/kab/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/kmr/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/oc/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/pl/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/th/
Translation: Pop OS/COSMIC Edit
2026-09-13 01:54:35 +02:00
85da7f90f2 chore: fige Cargo.lock 2026-09-10 18:12:37 +02:00
70c1765b1f Merge tag 'epoch-1.8.0' into local/libcosmic-path-patch
Epoch 1.8.0

# Conflicts:
#	Cargo.lock
2026-09-10 17:57:28 +02:00
20c47377a8 chore: fige Cargo.lock (reordonnancement patch.unused par cargo) 2026-09-04 10:48:53 +02:00
Jeremy Soller
26f6ffd3e6 Epoch 1.8.0 version update
Generated by cosmic-epoch scripts/version-update.sh
2026-09-03 13:18:38 -06:00
6150549a9b chore: fige Cargo.lock tel que resolu apres le merge 1.7.0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 07:58:51 +02:00
de9ae6890a Merge tag 'epoch-1.7.0' into local/libcosmic-path-patch
Epoch 1.7.0
2026-08-27 07:50:01 +02:00
Jeremy Soller
13b1d4aac0 Epoch 1.7.0 version update
Generated by cosmic-epoch scripts/version-update.sh
2026-08-25 11:39:01 -06:00
Michael Murphy
6c800ce1f1
i18n: translation update from Hosted Weblate (#610)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for [Pop OS/COSMIC
Edit](https://hosted.weblate.org/projects/pop-os/cosmic-edit/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/pop-os/cosmic-edit/matrix-auto.svg)
2026-08-24 20:52:37 +02:00
Jeremy Soller
0e9c927f1a
Fix tab auto focus on TabCloseForce (#603)
Auto focus should only trigger if the current tab is selected or else
closing an unfocused tab would move the focused tab.

See: pop-os/cosmic-files#1949

- [x] I have disclosed use of any AI generated code in my commit
messages.
- If you are using an LLM, and do not fully understand the changes it is
making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex
code that lacks enough context for a proper fix or feature inclusion.
This results in considerably longer code reviews. Due to this, AI
authored or partially authored PRs may be closed without comment.
- [x] I understand these changes in full and will be able to respond to
review comments.
- [x] My change is accurately described in the commit message.
- [x] My contribution is tested and working as described.
- [x] I have read the [Developer Certificate of
Origin](https://developercertificate.org/) and certify my contribution
under its conditions.
2026-08-20 19:02:21 -06:00
Jeremy Soller
b23384043e
feat: disable Cut and Copy buttons when no text is selected (#588)
- [x] I have disclosed use of any AI generated code in my commit
messages.
- If you are using an LLM, and do not fully understand the changes it is
making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex
code that lacks enough context for a proper fix or feature inclusion.
This results in considerably longer code reviews. Due to this, AI
authored or partially authored PRs may be closed without comment.
- [x] I understand these changes in full and will be able to respond to
review comments.
- [x] My change is accurately described in the commit message.
- [x] My contribution is tested and working as described.
- [x] I have read the [Developer Certificate of
Origin](https://developercertificate.org/) and certify my contribution
under its conditions.
2026-08-20 19:01:35 -06:00
Hosted Weblate
4a5be62b02
i18n: translation updates from weblate
Co-authored-by: Jens Peter Nielsen <mail@jp-nielsen.dk>
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-edit/da/
Translation: Pop OS/COSMIC Edit
2026-08-19 09:52:58 +00:00
nicole mikołajczyk
8c9c15de85 feat: disable Cut and Copy buttons when no text is selected
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
2026-08-18 15:49:12 -06:00
Josh Megnauth
e4006945c6
Fix tab auto focus on TabCloseForce
Auto focus should only trigger if the current tab is selected or else
closing an unfocused tab would move the focused tab.

See: pop-os/cosmic-files#1949
2026-08-01 20:11:53 -04:00
26 changed files with 932 additions and 976 deletions

View file

@ -1,8 +1,10 @@
- [ ] I have disclosed use of any AI generated code in my commit messages.
- If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment.
- [ ] I understand these changes in full and will be able to respond to review comments.
- [ ] My change is accurately described in the commit message.
- [ ] My contribution is tested and working as described.
- [ ] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
Replace this text with a description of your changes, and why these changes are important. Read and acknowledge the list below. PRs without a completed checkbox will be closed.
---
- I have not included any LLM (also known as AI) generated content in this PR, including code, comments, and descriptions.
- I understand these changes in full and will be able to respond to review comments.
- My change is accurately described in the commit message.
- My contribution is tested and working as described.
- I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
- [ ] I have read and followed all of the above requirements. For more information, see our [contributor guide](https://github.com/pop-os/pop/blob/master/CONTRIBUTING.md).

47
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: Continuous integration
on:
push:
branches: [master]
pull_request:
env:
CARGO_TERM_COLOR: always
DEBIAN_FRONTEND: noninteractive
jobs:
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: install toolchain
run: rustup toolchain install nightly --component rustfmt
- name: fmt
run: cargo +nightly fmt --all --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: install system dependencies
run: sudo apt-get update && sudo apt-get install -y pkg-config libglib2.0-dev libxkbcommon-dev libwayland-dev
- name: install toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: clippy
run: cargo clippy --all-features --all-targets -- -D warnings
test:
name: Test
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: install system dependencies
run: sudo apt-get update && sudo apt-get install -y pkg-config libglib2.0-dev libxkbcommon-dev libwayland-dev
- name: install toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: test
run: cargo test --all-features

14
.github/workflows/require-checklist.yml vendored Normal file
View file

@ -0,0 +1,14 @@
# From https://github.com/mheap/require-checklist-action, license MIT
name: Require Checklist
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
job1:
runs-on: ubuntu-latest
steps:
- uses: mheap/require-checklist-action@v2
with:
requireChecklist: true

1133
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package]
name = "cosmic-edit"
version = "1.6.0"
version = "1.10.0"
authors = ["Jeremy Soller <jeremy@system76.com>"]
edition = "2024"
license = "GPL-3.0-only"

70
cargo.just Normal file
View file

@ -0,0 +1,70 @@
cargo-target-dir := env('CARGO_TARGET_DIR', 'target')
# Compile with debug profile
[no-cd]
build-debug *args:
cargo build {{args}}
# Compile with release profile
[no-cd]
build-release *args: (build-debug '--release' args)
# Compile with a vendored tarball
[no-cd]
build-vendored *args: vendor-extract (build-release '--frozen --offline' args)
# Check for errors and linter warnings
[no-cd]
check *args:
cargo clippy --all-features {{args}} -- -W clippy::pedantic
# Runs a check with JSON message format for IDE integration
[no-cd]
check-json: (check '--message-format=json')
# Remove Cargo build artifacts
[no-cd]
clean:
cargo clean
# Also remove .cargo and vendored dependencies
[no-cd]
clean-dist: clean
rm -rf .cargo vendor vendor.tar target
# Run the application for testing purposes
[no-cd]
run *args:
cargo run {{args}}
# Run `cargo test`
[no-cd]
test *args:
cargo test {{args}}
# Vendor Cargo dependencies locally
[no-cd]
vendor:
#!/usr/bin/env bash
mkdir -p .cargo
cargo vendor --locked | head -n -1 > .cargo/config.toml
echo 'directory = "vendor"' >> .cargo/config.toml
echo >> .cargo/config.toml
echo '[env]' >> .cargo/config.toml
if [ -n "${SOURCE_DATE_EPOCH}" ]
then
source_date="$(date -d "@${SOURCE_DATE_EPOCH}" "+%Y-%m-%d")"
echo "VERGEN_GIT_COMMIT_DATE = \"${source_date}\"" >> .cargo/config.toml
fi
if [ -n "${SOURCE_GIT_HASH}" ]
then
echo "VERGEN_GIT_SHA = \"${SOURCE_GIT_HASH}\"" >> .cargo/config.toml
fi
tar pcf vendor.tar .cargo vendor
rm -rf .cargo vendor
# Extracts vendored dependencies
[no-cd]
vendor-extract:
rm -rf vendor
tar pxf vendor.tar

24
debian/changelog vendored
View file

@ -1,3 +1,27 @@
cosmic-edit (1.10.0) noble; urgency=medium
* Epoch 1.10.0 version update
-- Michael Murphy <michael@mmurphy.dev> Mon, 05 Oct 2026 21:19:33 +0200
cosmic-edit (1.9.0) noble; urgency=medium
* Epoch 1.9.0 version update
-- Michael Murphy <michael@mmurphy.dev> Mon, 14 Sep 2026 21:54:06 +0200
cosmic-edit (1.8.0) noble; urgency=medium
* Epoch 1.8.0 version update
-- Jeremy Soller <jeremy@system76.com> Wed, 02 Sep 2026 08:14:30 -0600
cosmic-edit (1.7.0) noble; urgency=medium
* Epoch 1.7.0 version update
-- Jeremy Soller <jeremy@system76.com> Tue, 25 Aug 2026 09:19:59 -0600
cosmic-edit (1.6.0) noble; urgency=medium
* Epoch 1.6.0 version update

5
debian/rules vendored
View file

@ -1,15 +1,12 @@
#!/usr/bin/make -f
export DESTDIR = debian/cosmic-edit
export VENDOR ?= 1
%:
dh $@
override_dh_auto_clean:
if ! ischroot && test "${VENDOR}" = "1"; then \
just vendor; \
fi
ischroot || just vendor
override_dh_auto_build:
just build-vendored

View file

@ -1,4 +1,6 @@
tar-ignore=.github
tar-ignore=.vscode
tar-ignore=target/.rustc_info.json
tar-ignore=target/CACHEDIR.TAG
tar-ignore=target/debug
tar-ignore=target/release
tar-ignore=vendor
tar-ignore=target

View file

@ -1,5 +1,5 @@
save = Gem
cancel = Annuller
cancel = Afbryd
quit = Afslut
cosmic-text-editor = COSMIC-teksteditor
new-document = Nyt dokument

0
i18n/fil/cosmic_edit.ftl Normal file
View file

View file

@ -53,14 +53,14 @@ dark = Sötét
light = Világos
syntax-dark = Sötét szintaxis
syntax-light = Világos szintaxis
default-font = Alapértelmezett betűtípus
default-font = Alapértelmezett betűkészlet
default-font-size = Alapértelmezett betűméret
default-zoom-step = Nagyítási mérték
### Keyboard shortcuts
keyboard-shortcuts = Gyorsbillentyűk
enable-vim-bindings = Vim billentyűkombinációk engedélyezése
enable-vim-bindings = Vim-billentyűkombinációk engedélyezése
# Find
find-placeholder = Keresés…
find-previous = Előző találat

View file

@ -1,9 +1,9 @@
cancel = Sefsex
cancel = Semmet
undo = Ssemmet
save = Sekles
quit = Tuffɣa
quit = Ffeɣ
replace = Semselsi
support = Tallalt
support = Tallelt
settings = Iɣewwaṛen
appearance = Timeẓri
theme = Asentel
@ -16,7 +16,7 @@ default-size = Tiddi tamezwert
zoom-out = Asemẓi
view = Wali
menu-settings = Iɣewwaṛen…
match-desktop = Amṣada d tnarit
match-desktop = Semṣada akked tnarit
file = Afaylu
new-window = Asfaylu amaynut
edit = Ẓreg

View file

@ -12,7 +12,7 @@ support = Piştgirî
quit = Biqedîne
find-placeholder = Bibîne...
copy = Jê bigire
paste = Pêve bike
paste = Pê ve bike
match-desktop = Bi sermaseyê re li hev bîne
select-all = Hemûyan hilbijêre
zoom-in = Nêzîk bike

View file

@ -1,8 +1,13 @@
settings = Paramètres
settings = Configuracion
appearance = Aparéncia
theme = Tèma
match-desktop = Assortir al burèu
dark = Fosc
dark = Escur
light = Clar
file = Fichièr
close-file = Tampar lo fichièr
cancel = Anullar
repository = Depaus
menu-settings = Configuracion...
quit = Quitar
replace = Remplaçar

View file

@ -1,5 +1,5 @@
cosmic-text-editor = Edytor Tekstu COSMIC
comment = Edytor tekstu pulpitu COSMIC
comment = Edytor tekstu dla środowiska COSMIC
new-document = Nowy dokument
open-project = Otwórz projekt
todo = TODO
@ -64,7 +64,7 @@ default-zoom-step = Stopniowanie powiększania
keyboard-shortcuts = Skróty klawiszowe
enable-vim-bindings = Włącz tryb Vim
# Find
find-placeholder = Szukaj…
find-placeholder = Wyszukaj…
find-previous = Znajdź poprzedni
find-next = Znajdź następny
replace-placeholder = Zastąp…
@ -106,8 +106,8 @@ cut = Wytnij
copy = Kopiuj
paste = Wklej
select-all = Zaznacz wszystko
find = Szukaj
find-in-project = Szukaj w projekcie…
find = Wyszukaj
find-in-project = Wyszukaj w projekcie…
spell-check = Sprawdź ortografię…
## View

View file

@ -0,0 +1,6 @@
cancel = ยกเลิก
settings = การตั้งค่า
dark = มืด
light = สว่าง
replace = แทนที่
appearance = ลักษณะ

3
rust-toolchain.toml Normal file
View file

@ -0,0 +1,3 @@
[toolchain]
channel = "1.93"
components = ["clippy", "rustfmt"]

View file

@ -112,17 +112,8 @@ impl Config {
}
}
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize, Default)]
pub struct ConfigState {
pub recent_files: VecDeque<PathBuf>,
pub recent_projects: VecDeque<PathBuf>,
}
impl Default for ConfigState {
fn default() -> Self {
Self {
recent_files: VecDeque::new(),
recent_projects: VecDeque::new(),
}
}
}

View file

@ -124,7 +124,7 @@ impl GitRepository {
msg.push_str("\nstderr> ");
msg.push_str(line);
}
Err(io::Error::new(io::ErrorKind::Other, msg))
Err(io::Error::other(msg))
}
}

View file

@ -11,7 +11,7 @@ use cosmic::{
cosmic_theme, executor,
font::Font,
iced::{
self, Alignment, Background, Color, Length, Limits, Point, Subscription,
self, Alignment, Background, Color, Length, Limits, Subscription,
advanced::graphics::text::font_system,
clipboard, event,
futures::{self, SinkExt},
@ -194,6 +194,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum Action {
Todo,
NoOp,
About,
CloseFile,
CloseProject(usize),
@ -244,6 +245,7 @@ impl Action {
fn message(&self, entity_opt: Option<Entity>) -> Message {
match self {
Self::Todo => Message::Todo,
Self::NoOp => Message::NoOp,
Self::About => Message::ToggleContextPage(ContextPage::About),
Self::CloseFile => Message::CloseFile,
Self::CloseProject(project_i) => Message::CloseProject(*project_i),
@ -326,6 +328,7 @@ impl PartialEq for WatcherWrapper {
}
}
#[allow(clippy::large_enum_variant)]
enum NewTab {
Tab(EditorTab),
Exists(Entity),
@ -371,6 +374,7 @@ pub enum Message {
Modifiers(Modifiers),
NewFile,
NewWindow,
NoOp,
NotifyEvent(notify::Event),
NotifyWatcher(WatcherWrapper),
OpenFile(PathBuf),
@ -400,7 +404,7 @@ pub enum Message {
SaveAsResult(segmented_button::Entity, DialogResult),
Scroll(f32),
SelectAll,
Surface(surface::Action),
Surface(surface::Action<Message>),
SystemThemeModeChange(cosmic_theme::ThemeMode),
SyntaxTheme(usize, bool),
TabActivate(segmented_button::Entity),
@ -409,7 +413,7 @@ pub enum Message {
TabClose(segmented_button::Entity),
TabCloseForce(segmented_button::Entity),
TabContextAction(segmented_button::Entity, Action),
TabContextMenu(segmented_button::Entity, Option<Point>),
TabContextMenu(segmented_button::Entity, bool),
TabNext,
TabPrev,
TabSetCursor(segmented_button::Entity, Cursor),
@ -526,7 +530,7 @@ impl App {
continue;
}
let entry_path = entry.path();
let node = match ProjectNode::new(&entry_path) {
let node = match ProjectNode::new(entry_path) {
Ok(ok) => ok,
Err(err) => {
log::error!(
@ -679,11 +683,11 @@ impl App {
//TODO: allow files to be open multiple times
let mut activate_opt = None;
for entity in self.tab_model.iter() {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity) {
if tab.path_opt.as_ref() == Some(&canonical) {
activate_opt = Some(entity);
break;
}
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity)
&& tab.path_opt.as_ref() == Some(&canonical)
{
activate_opt = Some(entity);
break;
}
}
if let Some(entity) = activate_opt {
@ -731,10 +735,10 @@ impl App {
}
let entities: Vec<_> = self.tab_model.iter().collect();
for entity in entities {
if self.tab_model.is_active(entity) {
if let Some(Tab::Editor(tab)) = self.tab_model.data_mut::<Tab>(entity) {
tab.set_config(&self.config);
}
if self.tab_model.is_active(entity)
&& let Some(Tab::Editor(tab)) = self.tab_model.data_mut::<Tab>(entity)
{
tab.set_config(&self.config);
}
}
}
@ -751,10 +755,10 @@ impl App {
}
fn save_config_state(&mut self) {
if let Some(ref config_state_handler) = self.config_state_handler {
if let Err(err) = self.config_state.write_entry(config_state_handler) {
log::error!("failed to save config_state: {}", err);
}
if let Some(ref config_state_handler) = self.config_state_handler
&& let Err(err) = self.config_state.write_entry(config_state_handler)
{
log::error!("failed to save config_state: {}", err);
}
}
@ -774,10 +778,10 @@ impl App {
Some(DialogPage::PromptSaveQuit(ref _entities)) => {
let mut unsaved = Vec::new();
for entity in self.tab_model.iter() {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity) {
if tab.changed() {
unsaved.push(entity);
}
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity)
&& tab.changed()
{
unsaved.push(entity);
}
}
if unsaved.is_empty() {
@ -916,16 +920,16 @@ impl App {
}
'tabs: for entity in self.tab_model.iter() {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity) {
if let Some(path) = &tab.path_opt {
for (_, project_path) in self.projects.iter() {
if path.starts_with(&project_path) {
// Do not watch tabs inside of already watched projects
continue 'tabs;
}
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity)
&& let Some(path) = &tab.path_opt
{
for (_, project_path) in self.projects.iter() {
if path.starts_with(project_path) {
// Do not watch tabs inside of already watched projects
continue 'tabs;
}
new_paths.insert((path.to_path_buf(), RecursiveMode::NonRecursive));
}
new_paths.insert((path.to_path_buf(), RecursiveMode::NonRecursive));
}
}
@ -1440,7 +1444,7 @@ impl Application for App {
let mut theme_names =
Vec::with_capacity(SYNTAX_SYSTEM.get().unwrap().theme_set.themes.len());
for (theme_name, _theme) in SYNTAX_SYSTEM.get().unwrap().theme_set.themes.iter() {
for theme_name in SYNTAX_SYSTEM.get().unwrap().theme_set.themes.keys() {
theme_names.push(theme_name.to_string());
}
@ -1459,7 +1463,7 @@ impl Application for App {
.comments(fl!("comment"))
.license("GPL-3.0-only")
.license_url("https://spdx.org/licenses/GPL-3.0-only")
.developers([("Jeremy Soller", "jeremy@system76.com")])
.developers([("System76", "info@system76.com")])
.links([
(fl!("repository"), "https://github.com/pop-os/cosmic-edit"),
(
@ -1649,9 +1653,7 @@ impl Application for App {
}
fn dialog(&self) -> Option<Element<'_, Self::Message>> {
let Some(ref dialog) = self.dialog_page_opt else {
return None;
};
let dialog = self.dialog_page_opt.as_ref()?;
let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing;
@ -1934,21 +1936,21 @@ impl Application for App {
return self.update_config();
}
Message::FindNext => {
if !self.find_search_value.is_empty() {
if let Some(Tab::Editor(tab)) = self.active_tab() {
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
tab.search(&regex, true, self.config.find_wrap_around);
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
if !self.find_search_value.is_empty()
&& let Some(Tab::Editor(tab)) = self.active_tab()
{
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
tab.search(&regex, true, self.config.find_wrap_around);
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
}
}
@ -1957,21 +1959,21 @@ impl Application for App {
return self.update_focus();
}
Message::FindPrevious => {
if !self.find_search_value.is_empty() {
if let Some(Tab::Editor(tab)) = self.active_tab() {
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
tab.search(&regex, false, self.config.find_wrap_around);
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
if !self.find_search_value.is_empty()
&& let Some(Tab::Editor(tab)) = self.active_tab()
{
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
tab.search(&regex, false, self.config.find_wrap_around);
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
}
}
@ -1980,27 +1982,27 @@ impl Application for App {
return self.update_focus();
}
Message::FindReplace => {
if !self.find_search_value.is_empty() {
if let Some(Tab::Editor(tab)) = self.active_tab() {
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
//TODO: support captures
tab.replace(
&regex,
&self.find_replace_value,
self.config.find_wrap_around,
);
return self.update(Message::TabChanged(self.tab_model.active()));
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
if !self.find_search_value.is_empty()
&& let Some(Tab::Editor(tab)) = self.active_tab()
{
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
//TODO: support captures
tab.replace(
&regex,
&self.find_replace_value,
self.config.find_wrap_around,
);
return self.update(Message::TabChanged(self.tab_model.active()));
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
}
}
@ -2009,27 +2011,27 @@ impl Application for App {
return self.update_focus();
}
Message::FindReplaceAll => {
if !self.find_search_value.is_empty() {
if let Some(Tab::Editor(tab)) = self.active_tab() {
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
//TODO: support captures
{
let mut editor = tab.editor.lock().unwrap();
editor.set_cursor(cosmic_text::Cursor::new(0, 0));
}
while tab.replace(&regex, &self.find_replace_value, false) {}
return self.update(Message::TabChanged(self.tab_model.active()));
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
if !self.find_search_value.is_empty()
&& let Some(Tab::Editor(tab)) = self.active_tab()
{
//TODO: do not compile find regex on every search?
match self.config.find_regex(&self.find_search_value) {
Ok(regex) => {
//TODO: support captures
{
let mut editor = tab.editor.lock().unwrap();
editor.set_cursor(cosmic_text::Cursor::new(0, 0));
}
while tab.replace(&regex, &self.find_replace_value, false) {}
return self.update(Message::TabChanged(self.tab_model.active()));
}
Err(err) => {
//TODO: put regex error in find box
log::warn!(
"failed to compile regex {:?}: {}",
self.find_search_value,
err
);
}
}
}
@ -2162,22 +2164,21 @@ impl Application for App {
}
}
}
Message::NoOp => {
// Do nothing
}
Message::NotifyEvent(event) => {
// Reload tabs that changed
let mut tab_reload = Vec::new();
for entity in self.tab_model.iter() {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity) {
if let Some(path) = &tab.path_opt {
if event.paths.contains(path) {
if tab.changed() {
log::warn!(
"file changed externally before being saved: {:?}",
path
);
} else {
tab_reload.push(entity);
}
}
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity)
&& let Some(path) = &tab.path_opt
&& event.paths.contains(path)
{
if tab.changed() {
log::warn!("file changed externally before being saved: {:?}", path);
} else {
tab_reload.push(entity);
}
}
}
@ -2275,7 +2276,7 @@ impl Application for App {
{
for (_, project_path) in self.projects.iter() {
for path in event.paths.iter() {
if let Ok(prefix) = path.strip_prefix(&project_path) {
if let Ok(prefix) = path.strip_prefix(project_path) {
// Manually ignore project .git folders
//TODO: use logic from ignore crate somehow?
if prefix.starts_with(".git") {
@ -2345,10 +2346,10 @@ impl Application for App {
{
let mut close = Vec::new();
for entity in self.tab_model.iter() {
if let Some(Tab::GitDiff(other_tab)) = self.tab_model.data::<Tab>(entity) {
if other_tab.diff.path == diff.path {
close.push(entity);
}
if let Some(Tab::GitDiff(other_tab)) = self.tab_model.data::<Tab>(entity)
&& other_tab.diff.path == diff.path
{
close.push(entity);
}
}
for entity in close {
@ -2666,10 +2667,10 @@ impl Application for App {
tab.path_opt = Some(paths.remove(0));
title_opt = Some(tab.title());
tab.save();
if let Some(path) = tab.path_opt.clone() {
if let Ok(canonical) = fs::canonicalize(&path) {
self.add_to_recents(&canonical);
}
if let Some(path) = tab.path_opt.clone()
&& let Ok(canonical) = fs::canonicalize(&path)
{
self.add_to_recents(&canonical);
}
}
if let Some(title) = title_opt {
@ -2707,9 +2708,7 @@ impl Application for App {
}
}
Message::Surface(a) => {
return cosmic::task::message(cosmic::Action::Cosmic(
cosmic::app::Action::Surface(a),
));
return cosmic::task::message(cosmic::Action::Surface(a));
}
Message::SystemThemeModeChange(_theme_mode) => {
return self.update_config();
@ -2788,7 +2787,9 @@ impl Application for App {
}
Message::TabCloseForce(entity) => {
// Activate closest item
if let Some(position) = self.tab_model.position(entity) {
if self.tab_model.active() == entity
&& let Some(position) = self.tab_model.position(entity)
{
if position > 0 {
self.tab_model.activate_position(position - 1);
} else {
@ -2815,15 +2816,15 @@ impl Application for App {
Message::TabContextAction(entity, action) => {
if let Some(Tab::Editor(tab)) = self.tab_model.data_mut::<Tab>(entity) {
// Close context menu
tab.context_menu = None;
tab.context_menu_open = false;
// Run action's message
return self.update(action.message(None));
}
}
Message::TabContextMenu(entity, position_opt) => {
Message::TabContextMenu(entity, open) => {
if let Some(Tab::Editor(tab)) = self.tab_model.data_mut::<Tab>(entity) {
// Update context menu
tab.context_menu = position_opt;
tab.context_menu_open = open;
}
}
Message::TabNext => {
@ -2845,13 +2846,7 @@ impl Application for App {
.tab_model
.position(self.tab_model.active())
.and_then(|i| (i as usize).checked_sub(1))
.unwrap_or_else(|| {
self.tab_model
.iter()
.count()
.checked_sub(1)
.unwrap_or_default()
});
.unwrap_or_else(|| self.tab_model.iter().count().saturating_sub(1));
let entity = self.tab_model.iter().nth(pos);
if let Some(entity) = entity {
@ -3028,12 +3023,19 @@ impl Application for App {
}
fn header_start(&self) -> Vec<Element<'_, Message>> {
let has_selection = match self.active_tab() {
Some(Tab::Editor(tab)) => tab.editor.lock().unwrap().selection() != Selection::None,
Some(Tab::GitDiff(_)) => false,
None => false,
};
vec![menu_bar(
&self.core,
&self.config,
&self.config_state,
&self.key_binds,
&self.projects,
has_selection,
)]
}
@ -3078,23 +3080,25 @@ impl Application for App {
.on_focus(Message::FindFocused(false))
.on_auto_scroll(Message::AutoScroll)
.on_changed(Message::TabChanged(tab_id))
.has_context_menu(tab.context_menu.is_some())
.on_context_menu(move |position_opt| {
Message::TabContextMenu(tab_id, position_opt)
});
.has_context_menu(tab.context_menu_open)
.on_context_menu(move |open| Message::TabContextMenu(tab_id, open));
if self.config.highlight_current_line {
text_box = text_box.highlight_current_line();
}
if self.config.line_numbers {
text_box = text_box.line_numbers();
}
let mut popover = widget::popover(text_box);
if let Some(point) = tab.context_menu {
popover = popover
.popup(menu::context_menu(&self.key_binds, tab_id))
.position(widget::popover::Position::Point(point));
let has_selection = tab.editor.lock().unwrap().selection() != Selection::None;
let mut context_menu = widget::context_menu(
text_box,
Some(menu::context_menu(&self.key_binds, tab_id, has_selection)),
)
.on_close(Message::TabContextMenu(tab_id, false))
.on_surface_action(Message::Surface);
if let Some(window_id) = self.core().main_window_id() {
context_menu = context_menu.window_id(window_id);
}
tab_column = tab_column.push(popover);
tab_column = tab_column.push(context_menu);
if self.config.vim_bindings {
let status = {
let editor = tab.editor.lock().unwrap();

View file

@ -1,21 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-only
use cosmic::widget::menu::Item as MenuItem;
use cosmic::widget::menu::action::MenuAction;
use cosmic::widget::menu::key_bind::KeyBind;
use cosmic::{
Element,
app::Core,
iced::{
Background, Border, Length, advanced::widget::text::Style as TextStyle, widget::column,
},
theme,
widget::{
self, divider,
menu::{ItemHeight, ItemWidth, menu_button},
responsive_menu_bar, segmented_button, space,
self,
menu::{ItemHeight, ItemWidth},
responsive_menu_bar, segmented_button,
},
};
use std::{collections::HashMap, path::PathBuf, sync::LazyLock};
use std::{
collections::HashMap,
path::{Path, PathBuf},
sync::LazyLock,
};
use crate::{Action, Config, ConfigState, Message, fl};
@ -63,7 +64,7 @@ fn truncate_middle(value: &str, max_chars: usize) -> String {
)
}
fn format_recent_menu_path(path: &PathBuf, home_dir_opt: Option<&PathBuf>) -> String {
fn format_recent_menu_path(path: &Path, home_dir_opt: Option<&PathBuf>) -> String {
const ELLIPSIS: &str = "...";
let display = if let Some(home_dir) = home_dir_opt {
@ -116,68 +117,49 @@ fn format_recent_menu_path(path: &PathBuf, home_dir_opt: Option<&PathBuf>) -> St
truncate_middle(&display, RECENT_MENU_LABEL_MAX_CHARS)
}
pub fn context_menu<'a>(
/// A context menu action dispatched to the tab the menu was opened on.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TabAction(pub segmented_button::Entity, pub Action);
impl MenuAction for TabAction {
type Message = Message;
fn message(&self) -> Message {
Message::TabContextAction(self.0, self.1)
}
}
pub fn context_menu(
key_binds: &HashMap<KeyBind, Action>,
entity: segmented_button::Entity,
) -> Element<'a, Message> {
fn key_style(theme: &cosmic::Theme) -> TextStyle {
// TODO use wayland popups
let mut color = theme.cosmic().background(false).component.on;
color.alpha *= 0.75;
TextStyle {
color: Some(color.into()),
..Default::default()
has_selection: bool,
) -> Vec<widget::menu::Tree<Message>> {
let item =
|label: String, action: Action| MenuItem::Button(label, None, TabAction(entity, action));
let optional = |label: String, action: Action, enabled: bool| {
if enabled {
MenuItem::Button(label, None, TabAction(entity, action))
} else {
MenuItem::ButtonDisabled(label, None, TabAction(entity, action))
}
}
let menu_item = |menu_label, menu_action| {
let mut key = String::new();
for (key_bind, key_action) in key_binds.iter() {
if key_action == &menu_action {
key = key_bind.to_string();
break;
}
}
menu_button(vec![
widget::text(menu_label).into(),
space::horizontal().into(),
widget::text(key)
.class(theme::Text::Custom(key_style))
.into(),
])
.on_press(Message::TabContextAction(entity, menu_action))
};
widget::container(
cosmic::widget::menu::menu_column::MenuColumn::with_children([
menu_item(fl!("undo"), Action::Undo).into(),
menu_item(fl!("redo"), Action::Redo).into(),
divider::horizontal::light().into(),
menu_item(fl!("cut"), Action::Cut).into(),
menu_item(fl!("copy"), Action::Copy).into(),
menu_item(fl!("paste"), Action::Paste).into(),
menu_item(fl!("select-all"), Action::SelectAll).into(),
]),
let key_binds: HashMap<KeyBind, TabAction> = key_binds
.iter()
.map(|(key_bind, action)| (key_bind.clone(), TabAction(entity, *action)))
.collect();
widget::menu::items(
&key_binds,
vec![
item(fl!("undo"), Action::Undo),
item(fl!("redo"), Action::Redo),
MenuItem::Divider,
optional(fl!("cut"), Action::Cut, has_selection),
optional(fl!("copy"), Action::Copy, has_selection),
item(fl!("paste"), Action::Paste),
item(fl!("select-all"), Action::SelectAll),
],
)
.padding(1)
//TODO: move style to libcosmic
.style(|theme| {
let cosmic = theme.cosmic();
let component = &cosmic.background(false).component;
widget::container::Style {
icon_color: Some(component.on.into()),
text_color: Some(component.on.into()),
background: Some(Background::Color(component.base.into())),
border: Border {
radius: cosmic.radius_s().map(|x| x + 1.0).into(),
width: 1.0,
color: component.divider.into(),
},
..Default::default()
}
})
.width(Length::Fixed(240.0))
.into()
}
pub fn menu_bar<'a>(
@ -185,7 +167,8 @@ pub fn menu_bar<'a>(
config: &Config,
config_state: &ConfigState,
key_binds: &HashMap<KeyBind, Action>,
projects: &Vec<(String, PathBuf)>,
projects: &[(String, PathBuf)],
has_selection: bool,
) -> Element<'a, Message> {
//TODO: port to libcosmic
let menu_tab_width = |tab_width: u16| {
@ -278,8 +261,16 @@ pub fn menu_bar<'a>(
MenuItem::Button(fl!("undo"), None, Action::Undo),
MenuItem::Button(fl!("redo"), None, Action::Redo),
MenuItem::Divider,
MenuItem::Button(fl!("cut"), None, Action::Cut),
MenuItem::Button(fl!("copy"), None, Action::Copy),
if has_selection {
MenuItem::Button(fl!("cut"), None, Action::Cut)
} else {
MenuItem::ButtonDisabled(fl!("cut"), None, Action::NoOp)
},
if has_selection {
MenuItem::Button(fl!("copy"), None, Action::Copy)
} else {
MenuItem::ButtonDisabled(fl!("copy"), None, Action::NoOp)
},
MenuItem::Button(fl!("paste"), None, Action::Paste),
MenuItem::Button(fl!("select-all"), None, Action::SelectAll),
MenuItem::Divider,

View file

@ -29,15 +29,15 @@ impl ProjectNode {
let path = fs::canonicalize(path)?;
let name = path
.file_name()
.ok_or(io::Error::new(
io::ErrorKind::Other,
format!("path {:?} has no file name", path),
))?
.ok_or(io::Error::other(format!(
"path {:?} has no file name",
path
)))?
.to_str()
.ok_or(io::Error::new(
io::ErrorKind::Other,
format!("path {:?} is not valid UTF-8", path),
))?
.ok_or(io::Error::other(format!(
"path {:?} is not valid UTF-8",
path
)))?
.to_string();
Ok(if path.is_dir() {
Self::Folder {

View file

@ -54,10 +54,10 @@ impl ProjectSearchResult {
}
};
if let Some(file_type) = entry.file_type() {
if file_type.is_dir() {
continue;
}
if let Some(file_type) = entry.file_type()
&& file_type.is_dir()
{
continue;
}
let entry_path = entry.path();

View file

@ -1,9 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use cosmic::{
iced::{Point, advanced::graphics::text::font_system},
widget::icon,
};
use cosmic::{iced::advanced::graphics::text::font_system, widget::icon};
use cosmic_files::mime_icon::{FALLBACK_MIME_ICON, mime_for_path, mime_icon};
use cosmic_text::{Attrs, Buffer, Cursor, Edit, Selection, Shaping, SyntaxEditor, ViEditor, Wrap};
use regex::Regex;
@ -28,6 +25,7 @@ fn editor_text(editor: &ViEditor<'static, 'static>) -> String {
})
}
#[allow(clippy::large_enum_variant)]
pub enum Tab {
Editor(EditorTab),
GitDiff(GitDiffTab),
@ -51,7 +49,7 @@ pub struct EditorTab {
pub path_opt: Option<PathBuf>,
attrs: Attrs<'static>,
pub editor: Mutex<ViEditor<'static, 'static>>,
pub context_menu: Option<Point>,
pub context_menu_open: bool,
pub zoom_adj: i8,
}
@ -75,7 +73,7 @@ impl EditorTab {
path_opt: None,
attrs,
editor: Mutex::new(ViEditor::new(editor)),
context_menu: None,
context_menu_open: false,
zoom_adj,
};
@ -316,7 +314,7 @@ impl EditorTab {
.filter_map(|m| {
if cursor.line != start_line
|| m.start() >= cursor.index
|| m.start() < cursor.index && wrapped == true
|| m.start() < cursor.index && wrapped
{
Some((m.start(), m.len()))
} else {
@ -393,7 +391,7 @@ impl EditorTab {
if cursor.line != start_line
|| m.start() > cursor.index
|| m.start() == cursor.index && current_selection == Selection::None
|| m.start() < cursor.index && wrapped == true
|| m.start() < cursor.index && wrapped
{
Some((m.start(), m.end()))
} else {
@ -436,7 +434,7 @@ impl EditorTab {
if cursor.line != start_line
|| m.start() < cursor.index
|| m.start() == cursor.index && current_selection == Selection::None
|| m.start() > cursor.index && wrapped == true
|| m.start() > cursor.index && wrapped
{
Some((m.start(), m.end()))
} else {

View file

@ -51,7 +51,7 @@ pub struct TextBox<'a, Message> {
on_focus: Option<Message>,
click_timing: Duration,
has_context_menu: bool,
on_context_menu: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
on_context_menu: Option<Box<dyn Fn(bool) -> Message + 'a>>,
highlight_current_line: bool,
line_numbers: bool,
}
@ -107,10 +107,7 @@ where
self
}
pub fn on_context_menu(
mut self,
on_context_menu: impl Fn(Option<Point>) -> Message + 'a,
) -> Self {
pub fn on_context_menu(mut self, on_context_menu: impl Fn(bool) -> Message + 'a) -> Self {
self.on_context_menu = Some(Box::new(on_context_menu));
self
}
@ -320,9 +317,8 @@ where
editor.with_buffer(|buffer| {
let mut layout_lines = 0;
for line in buffer.lines.iter() {
match line.layout_opt() {
Some(layout) => layout_lines += layout.len(),
None => (),
if let Some(layout) = line.layout_opt() {
layout_lines += layout.len()
}
}
@ -758,7 +754,7 @@ where
match editor.buffer_ref() {
cosmic_text::BufferRef::Arc(buffer) => {
renderer.fill_raw(Raw {
buffer: Arc::downgrade(&buffer),
buffer: Arc::downgrade(buffer),
position: pos,
color: Color::from_rgba(1.0, 1.0, 1.0, 1.0),
clip_bounds,
@ -1098,15 +1094,13 @@ where
editor.set_redraw(true);
shell.capture_event();
}
Named::Tab => {
if !modifiers.control() && !modifiers.alt() {
if modifiers.shift() {
editor.action(Action::Unindent);
} else {
editor.action(Action::Indent);
}
shell.capture_event();
Named::Tab if !modifiers.control() && !modifiers.alt() => {
if modifiers.shift() {
editor.action(Action::Unindent);
} else {
editor.action(Action::Indent);
}
shell.capture_event();
}
_ => (),
},
@ -1155,7 +1149,7 @@ where
InputMethodEvent::Commit(text) => {
if state.is_focused {
editor.start_change();
editor.insert_string(&text, None);
editor.insert_string(text, None);
editor.finish_change();
shell.capture_event();
}
@ -1177,13 +1171,13 @@ where
let y = y_logical * scale_factor;
// Do this first as the horizontal scrollbar is on top of the buffer
if let Some(scrollbar_h_rect) = state.scrollbar_h_rect.get() {
if scrollbar_h_rect.contains(Point::new(x_logical, y_logical)) {
state.dragging = Some(Dragging::ScrollbarH {
start_x: x,
start_scroll: editor.with_buffer(|buffer| buffer.scroll()),
});
}
if let Some(scrollbar_h_rect) = state.scrollbar_h_rect.get()
&& scrollbar_h_rect.contains(Point::new(x_logical, y_logical))
{
state.dragging = Some(Dragging::ScrollbarH {
start_x: x,
start_scroll: editor.with_buffer(|buffer| buffer.scroll()),
});
}
if matches!(state.dragging, Some(Dragging::ScrollbarH { .. })) {
@ -1210,7 +1204,7 @@ where
ClickKind::Single
};
let maybe_anchor = if state.modifiers.shift() {
state.shift_anchor.lock().unwrap().clone()
*state.shift_anchor.lock().unwrap()
} else {
None
};
@ -1267,14 +1261,9 @@ where
// Update context menu state
if let Some(on_context_menu) = &self.on_context_menu {
shell.publish((on_context_menu)(if self.has_context_menu {
None
} else {
match button {
Button::Right => Some(p),
_ => None,
}
}));
shell.publish((on_context_menu)(
!self.has_context_menu && matches!(button, Button::Right),
));
}
shell.capture_event();
@ -1396,11 +1385,9 @@ where
shell.capture_event();
}
}
Event::Window(WindowEvent::RedrawRequested(_now)) => {
if state.is_focused {
state.caret_position = editor.cursor_position().unwrap_or(state.caret_position);
shell.request_input_method(&self.input_method(state, scale_factor, layout));
}
Event::Window(WindowEvent::RedrawRequested(_now)) if state.is_focused => {
state.caret_position = editor.cursor_position().unwrap_or(state.caret_position);
shell.request_input_method(&self.input_method(state, scale_factor, layout));
}
_ => (),
}