From c17753ce60cb2880df2a0e9d698eff47ef706a65 Mon Sep 17 00:00:00 2001 From: Wael Mahrous Date: Wed, 30 Oct 2024 20:53:43 +0100 Subject: [PATCH 1/4] Add option to open slide in editor This allows the user to edit the currently open slide with the command ctrl+o. Must be a session in tmux. Currently only opens it in vim, but I'll add more so that you can change to an editor of choice in a config file. --- internal/model/model.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/model/model.go b/internal/model/model.go index 145cfc06..c6e3f435 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "os/exec" "strings" "time" @@ -177,6 +178,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case "ctrl+c", "q": return m, tea.Quit + case "ctrl+o": + // Opens the current slide in vim + err := m.openNewWindow() + if err != nil { + return m, nil + } default: newState := navigation.Navigate(navigation.State{ Buffer: m.buffer, @@ -314,3 +321,9 @@ func (m *Model) SetPage(page int) { func (m *Model) Pages() []string { return m.Slides } + +// Opens the current slide as a split window in tmux. +func (m *Model) openNewWindow() error { + cmd := exec.Command("tmux", "split-window", "-h", "vim", m.FileName) + return cmd.Start() +} From 14b6e1e17be6fa2c5d249bf0473faf2c9d70a0e2 Mon Sep 17 00:00:00 2001 From: Wael Mahrous Date: Thu, 31 Oct 2024 00:58:13 +0100 Subject: [PATCH 2/4] Move to an editor package A better structure that makes it easier to add new editing capabilities later on. --- internal/editor/editor.go | 31 +++++++++++++++++++++++++++++++ internal/model/model.go | 12 +++--------- main.go | 2 ++ 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 internal/editor/editor.go diff --git a/internal/editor/editor.go b/internal/editor/editor.go new file mode 100644 index 00000000..fd1b9071 --- /dev/null +++ b/internal/editor/editor.go @@ -0,0 +1,31 @@ +package editor + +import ( + "os/exec" + + "github.com/muesli/coral" +) + +var defaultEditor = "vim" + +var ( + name string +) + +// Opens the current slide as a split window in tmux. +func OpenNewWindow(fileName string) error { + var cmd *exec.Cmd + + switch name { + case "vim", "nvim": + cmd = exec.Command("tmux", "split-window", "-h", name, fileName) + case "code": + cmd = exec.Command(name, fileName) + } + + return cmd.Start() +} + +func InitEditorFlag(rootCmd *coral.Command) { + rootCmd.PersistentFlags().StringVarP(&name, "editor", "e", defaultEditor, "Specify the editor to use") +} diff --git a/internal/model/model.go b/internal/model/model.go index c6e3f435..f75842f4 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -7,11 +7,11 @@ import ( "fmt" "io" "os" - "os/exec" "strings" "time" "github.com/atotto/clipboard" + "github.com/maaslalani/slides/internal/editor" "github.com/maaslalani/slides/internal/file" "github.com/maaslalani/slides/internal/navigation" "github.com/maaslalani/slides/internal/process" @@ -179,8 +179,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q": return m, tea.Quit case "ctrl+o": - // Opens the current slide in vim - err := m.openNewWindow() + // Opens the current slide in an editor + err := editor.OpenNewWindow(m.FileName) if err != nil { return m, nil } @@ -321,9 +321,3 @@ func (m *Model) SetPage(page int) { func (m *Model) Pages() []string { return m.Slides } - -// Opens the current slide as a split window in tmux. -func (m *Model) openNewWindow() error { - cmd := exec.Command("tmux", "split-window", "-h", "vim", m.FileName) - return cmd.Start() -} diff --git a/main.go b/main.go index 4c4af825..faf37973 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/maaslalani/slides/internal/cmd" + "github.com/maaslalani/slides/internal/editor" "github.com/maaslalani/slides/internal/model" "github.com/maaslalani/slides/internal/navigation" "github.com/muesli/coral" @@ -47,6 +48,7 @@ func init() { rootCmd.AddCommand( cmd.ServeCmd, ) + editor.InitEditorFlag(rootCmd) rootCmd.CompletionOptions.DisableDefaultCmd = true } From 1d6f46e4e4015e610adef0155bf5ac85d4f752a4 Mon Sep 17 00:00:00 2001 From: Wael Mahrous Date: Thu, 31 Oct 2024 17:03:05 +0100 Subject: [PATCH 3/4] Switched editor to tea.Cmd implementation --- internal/editor/editor.go | 20 +++++--------------- internal/model/model.go | 5 +---- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/internal/editor/editor.go b/internal/editor/editor.go index fd1b9071..394f1ab7 100644 --- a/internal/editor/editor.go +++ b/internal/editor/editor.go @@ -3,29 +3,19 @@ package editor import ( "os/exec" + tea "github.com/charmbracelet/bubbletea" "github.com/muesli/coral" ) -var defaultEditor = "vim" - var ( - name string + program = "vim" ) // Opens the current slide as a split window in tmux. -func OpenNewWindow(fileName string) error { - var cmd *exec.Cmd - - switch name { - case "vim", "nvim": - cmd = exec.Command("tmux", "split-window", "-h", name, fileName) - case "code": - cmd = exec.Command(name, fileName) - } - - return cmd.Start() +func OpenNewWindow(fileName string) tea.Cmd { + return tea.ExecProcess(exec.Command(program, fileName), nil) } func InitEditorFlag(rootCmd *coral.Command) { - rootCmd.PersistentFlags().StringVarP(&name, "editor", "e", defaultEditor, "Specify the editor to use") + rootCmd.PersistentFlags().StringVarP(&program, "editor", "e", program, "Specify the editor to use") } diff --git a/internal/model/model.go b/internal/model/model.go index f75842f4..b32099fa 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -180,10 +180,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "ctrl+o": // Opens the current slide in an editor - err := editor.OpenNewWindow(m.FileName) - if err != nil { - return m, nil - } + return m, editor.OpenNewWindow(m.FileName) default: newState := navigation.Navigate(navigation.State{ Buffer: m.buffer, From 7de24f7ceafc0b0c57a178a930e387d5df7a51a9 Mon Sep 17 00:00:00 2001 From: Wael Mahrous Date: Thu, 31 Oct 2024 18:41:48 +0100 Subject: [PATCH 4/4] Editor can jump to line number in vim/nvim --- internal/editor/editor.go | 61 +++++++++++++++++++++++++++++++++++---- internal/model/model.go | 2 +- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/internal/editor/editor.go b/internal/editor/editor.go index 394f1ab7..ae8f1391 100644 --- a/internal/editor/editor.go +++ b/internal/editor/editor.go @@ -1,19 +1,70 @@ package editor import ( + "fmt" + "os" "os/exec" + "strings" tea "github.com/charmbracelet/bubbletea" "github.com/muesli/coral" ) -var ( - program = "vim" -) +var program = func() string { + if editor := os.Getenv("EDITOR"); editor != "" { + return editor + } + return "vim" +}() // Opens the current slide as a split window in tmux. -func OpenNewWindow(fileName string) tea.Cmd { - return tea.ExecProcess(exec.Command(program, fileName), nil) +func OpenNewWindow(fileName string, slide string) tea.Cmd { + var c *exec.Cmd + + editorName := GetEditorName(program) + + switch editorName { + case "vim", "nvim": + c = exec.Command(program, fmt.Sprintf("+%d", GetLineNumber(fileName, slide)), fileName) + case "code": + c = exec.Command(program, fileName, "--go-to", fmt.Sprintf("+%d", GetLineNumber(fileName, slide))) + default: + c = exec.Command(program, fileName) + } + + return tea.ExecProcess(c, nil) +} + +func linesMatch(lines []string, sLines []string, start int) bool { + for j := range sLines { + if strings.TrimSpace(lines[start+j]) != strings.TrimSpace(sLines[j]) { + return false + } + } + return true +} + +func GetLineNumber(fileName string, slide string) int { + b, err := os.ReadFile(fileName) + if err != nil { + return -1 + } + + lines := strings.Split(string(b), "\n") + sLines := strings.Split(slide, "\n") + + for i := range lines { + if linesMatch(lines, sLines, i) { + return i + } + } + + return -1 +} + +func GetEditorName(editorPath string) string { + parts := strings.Split(editorPath, "/") + return parts[len(parts)-1] } func InitEditorFlag(rootCmd *coral.Command) { diff --git a/internal/model/model.go b/internal/model/model.go index b32099fa..98f92237 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -180,7 +180,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "ctrl+o": // Opens the current slide in an editor - return m, editor.OpenNewWindow(m.FileName) + return m, editor.OpenNewWindow(m.FileName, m.Slides[m.Page]) default: newState := navigation.Navigate(navigation.State{ Buffer: m.buffer,