-
Notifications
You must be signed in to change notification settings - Fork 2
/
line.go
133 lines (115 loc) · 3 KB
/
line.go
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
// rem - A tool to remember things on the command line.
// Copyright (C) 2015 Martin Borho (martin@borho.net)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"regexp"
"strings"
"github.com/shirou/gopsutil/v3/process"
"golang.org/x/sys/unix"
)
type Line struct {
line string
cmd string
tag string
execFlag string
}
// Read incoming string into Line struct.
func (l *Line) read(line string) {
re := regexp.MustCompile("^#([^ ]+)?#")
l.line = line
if tagMatch := re.FindSubmatch([]byte(line)); tagMatch != nil {
l.tag = string(tagMatch[1])
l.cmd = line[len(l.tag)+2:]
} else {
// no tag found, simple command
l.cmd = line
}
}
// Edit opens the line in a text editor and returns the edited string.
func (l *Line) edit() (string, error) {
editor := os.Getenv("EDITOR")
if editor == "" {
editor = "nano" // Fallback to 'nano' as the default editor if $EDITOR is not set
}
file, err := ioutil.TempFile("/tmp", "tmp-*.txt")
if err != nil {
return "", err
}
defer os.Remove(file.Name())
_, err = file.WriteString(l.cmd)
if err != nil {
return "", err
}
file.Close()
cmd := exec.Command(editor, file.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return "", err
}
modifiedText, err := ioutil.ReadFile(file.Name())
if err != nil {
return "", err
}
return strings.ReplaceAll(strings.ReplaceAll(strings.TrimSpace(string(modifiedText)), "\r\n", " "), "\n", " "), nil
}
func (l *Line) execute(printCmd bool) error {
// get the pid of the calling shell
p, err := process.NewProcess(int32(os.Getppid()))
if err != nil {
return err
}
// path of calling shell
callerPath, err := p.Exe()
if err != nil {
return err
}
// define 'execute' flag if not set
if l.execFlag == "" {
l.execFlag = "-c"
}
// print cmd before executing
if printCmd == true {
fmt.Println(l.cmd)
}
// /bin/bash -c "ls -la"
execParts := []string{callerPath, l.execFlag, l.cmd}
// replace the current process
err = unix.Exec(callerPath, execParts, os.Environ())
if err != nil {
return err
}
return nil
}
// Prints line to tabwriter.
func (l *Line) print(w io.Writer, index int, withTag bool) {
if withTag {
tag := ""
if tag = l.tag; tag == "" {
tag = " - "
}
fmt.Fprintf(w, " %d\t%s\t%s\n", index, tag, l.cmd)
} else {
fmt.Fprintf(w, " %d\t%s\n", index, l.cmd)
}
}