├── .gitignore
├── LICENSE
├── README.md
├── build_mac.sh
├── build_win.sh
├── go.mod
├── go.sum
├── main.go
├── pipe
├── column2row.go
├── field.go
├── fmtrow.go
├── join.go
├── line.go
├── match.go
├── pipe.go
├── registry.go
├── replace.go
├── rsplit.go
├── surround.go
├── table.go
└── trim.go
├── resource
├── pipeline.icns
├── pipeline.ico
└── pipeline.png
└── screenshot
├── addquotation.gif
├── commatolines.gif
├── findimageurl.gif
└── screenshot1.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
17 | build/
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Allen Dang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PipeIt
2 |
3 | PipeIt is a text transformation, conversion, cleansing and extraction tool.
4 |
5 |
6 |
7 | # Features
8 |
9 | - Split - split text to text array by given separator.
10 | - RegexpSplit - split text to text array by given regexp expression.
11 | - Fields - Fields splits the string s around each instance of one or more consecutive white space characters.
12 | - Match - filter text array by regexp.
13 | - Replace - replace each element of a text array.
14 | - Surround - add prefix or suffix to each lement of a text array.
15 | - Trim - Trim returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed.
16 | - Join - join text array to single line of text by given separator.
17 | - Line - output text array line by line.
18 |
19 | And more pipes are comming...
20 |
21 | (More important, tell me your case will help me to create more pipes which will actually useful.)
22 |
23 | PipeIt also supports to read from Stdin, so you could pipe data using "cat file | PipeIt".
24 |
25 | # Usage
26 |
27 | ## Extract image links from a html source
28 |
29 |
30 |
31 | ## Add single quotation mark to every words
32 |
33 |
34 |
35 | ## Replace the comma separated string to lines
36 |
37 |
38 |
39 | # The reason for creating it
40 |
41 | First of all, to test the GUI framework created by me, [giu](https://github.com/AllenDang/giu), for a real project.
42 |
43 | It turns out giu is really useful for this kind of application. It just costs me 6 hours to build it from ground.
44 |
45 | And I have this idea for years, to create a text process pipeline, to ease my daily text processing pain.
46 |
47 | Hope it could be useful to you as well. :)
48 |
--------------------------------------------------------------------------------
/build_mac.sh:
--------------------------------------------------------------------------------
1 | gmdeploy -os=darwin -icon=./resource/pipeline.icns .
2 |
--------------------------------------------------------------------------------
/build_win.sh:
--------------------------------------------------------------------------------
1 | echo "
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | PerMonitorV2, PerMonitor
13 | True
14 |
15 |
16 |
17 | " > PipeIt.exe.manifest
18 |
19 | rsrc -manifest PipeIt.exe.manifest -ico ./resource/pipeline.ico -arch amd64 -o rsrc.syso
20 |
21 | go build -ldflags='-s -w -H windowsgui -linkmode external -extldflags -static' .
22 |
23 | rm PipeIt.exe.manifest
24 | rm rsrc.syso
25 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/AllenDang/PipeIt
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/AllenDang/giu v0.6.1-0.20220113131307-67f04e276bc6
7 | github.com/davecgh/go-spew v1.1.1 // indirect
8 | github.com/kr/pretty v0.1.0 // indirect
9 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
10 | golang.org/x/net v0.0.0-20220111093109-d55c255bac03 // indirect
11 | golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
12 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
13 | )
14 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/AllenDang/giu v0.6.1-0.20220113131307-67f04e276bc6 h1:VJ6hUagTss1Ypkb+FWjRQ6PR2lJ0MKWmA0ruh431j+w=
2 | github.com/AllenDang/giu v0.6.1-0.20220113131307-67f04e276bc6/go.mod h1:r1J1d26AT9OBlMF6xL7tBgUE9xHzJKGjSvHDysoc18U=
3 | github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8 h1:dKZMqib/yUDoCFigmz2agG8geZ/e3iRq304/KJXqKyw=
4 | github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8/go.mod h1:b4uuDd0s6KRIPa84cEEchdQ9ICh7K0OryZHbSzMca9k=
5 | github.com/AllenDang/imgui-go v1.12.1-0.20220112081257-3c75746ab409 h1:IfyLHdkAfYaGkCzScI/ahbqE5FL1kuN/iwLtw7Z+p3s=
6 | github.com/AllenDang/imgui-go v1.12.1-0.20220112081257-3c75746ab409/go.mod h1:lSWsbR1qGBZz405YzfHXcwEyWQq206QC7cYMHoLvmI4=
7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10 | github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
11 | github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
12 | github.com/go-gl/gl v0.0.0-20210315015930-ae072cafe09d/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
13 | github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
14 | github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
15 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec h1:3FLiRYO6PlQFDpUU7OEFlWgjGD1jnBIVSJ5SYRWk+9c=
16 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
17 | github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
18 | github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
19 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
20 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
21 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
22 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
23 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
24 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
25 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
26 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
27 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
28 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
29 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
30 | github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
31 | github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
32 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
33 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
34 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
35 | golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
36 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
37 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
38 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
39 | golang.org/x/net v0.0.0-20220111093109-d55c255bac03 h1:0FB83qp0AzVJm+0wcIlauAjJ+tNdh7jLuacRYCIVv7s=
40 | golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
41 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
42 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
43 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
44 | golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
45 | golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
46 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
47 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
48 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
49 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
50 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
51 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
52 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
53 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
54 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/AllenDang/PipeIt/pipe"
10 | g "github.com/AllenDang/giu"
11 | )
12 |
13 | const (
14 | saveDir string = "Save"
15 | )
16 |
17 | var (
18 | input string
19 | output string
20 |
21 | pipeHint string
22 |
23 | pipeline pipe.Pipeline
24 |
25 | savePipelineName string
26 | savedPipelines []string
27 | selectedIndex int32
28 | comboPreview string
29 | )
30 |
31 | func changed() {
32 | if len(pipeline) > 0 {
33 | pipeHint = "Pipeline (left click pipe to config, right click to delete)"
34 | } else {
35 | pipeHint = "Pipeline (click + to add a pipe)"
36 | }
37 |
38 | output = ""
39 |
40 | var data interface{} = input
41 | for _, p := range pipeline {
42 | data = p.Process(data)
43 | }
44 |
45 | output = fmt.Sprint(data)
46 | }
47 |
48 | func buildConfigMenu(index int, configUI g.Layout) g.Layout {
49 | inType := pipe.DataTypeString
50 | outType := pipeline[index].GetInputType()
51 |
52 | if index > 0 {
53 | inType = pipeline[index-1].GetOutputType()
54 | }
55 |
56 | betweenPipes := pipe.QueryPipesBetween(inType, outType)
57 |
58 | var addBeforeMenuItems g.Layout
59 | for i, p := range betweenPipes {
60 | builder := p.Builder
61 | addBeforeMenuItems = append(addBeforeMenuItems, g.Selectable(fmt.Sprintf("%s##%d-%d", p.Name, index, i)).OnClick(func() {
62 | pipeline = append(pipeline[:index], append(pipe.Pipeline{builder()}, pipeline[index:]...)...)
63 | changed()
64 | }))
65 | addBeforeMenuItems = append(addBeforeMenuItems, g.Tooltip(p.Tip))
66 | }
67 |
68 | var addBeforeMenu g.Layout
69 | if len(addBeforeMenuItems) > 0 {
70 | addBeforeMenu = append(addBeforeMenu, g.Menu(fmt.Sprintf("Add before##%d", index)).Layout(addBeforeMenuItems))
71 | } else {
72 | addBeforeMenu = append(addBeforeMenu, g.Menu(fmt.Sprintf("Add before##%d", index)).Layout(g.Layout{g.Label("No suitable pipe")}))
73 | }
74 |
75 | return g.Layout{
76 | g.Custom(func() {
77 | if configUI != nil {
78 | g.ContextMenu().ID(fmt.Sprintf("%s##%d", "configMenu", index)).MouseButton(g.MouseButtonLeft).Layout(configUI).Build()
79 | }
80 | }),
81 | g.ContextMenu().ID(fmt.Sprintf("%s##%d", "opMenu", index)).MouseButton(g.MouseButtonRight).Layout(g.Layout{
82 | addBeforeMenu,
83 | g.Selectable("Delete").OnClick(func() {
84 | pipeline = append(pipeline[:index], pipeline[index+1:]...)
85 | changed()
86 | }),
87 | }),
88 | }
89 | }
90 |
91 | func buildPipesMenu() g.Widget {
92 | var widgets []g.Widget
93 | queryType := pipe.DataTypeString
94 | if len(pipeline) > 0 {
95 | queryType = pipeline[len(pipeline)-1].GetOutputType()
96 | }
97 |
98 | pipBuilders := pipe.QueryPipes(queryType)
99 | if pipBuilders == nil {
100 | widgets = append(widgets, g.Label("No suitable pipe"))
101 | } else {
102 | for i, pb := range pipBuilders {
103 | builder := pb.Builder
104 | widgets = append(widgets,
105 | g.Selectable(fmt.Sprintf("%s##%d", pb.Name, i)).OnClick(func() {
106 | pipeline = append(pipeline, builder())
107 | changed()
108 | }),
109 | g.Tooltip(pb.Tip),
110 | )
111 | }
112 | }
113 |
114 | return g.ContextMenu().ID("AvailabePipes").MouseButton(g.MouseButtonLeft).Layout(widgets...)
115 | }
116 |
117 | func buildPipeLineWidgets(pipes pipe.Pipeline) g.Widget {
118 | var widgets []g.Widget
119 | if len(pipes) > 0 {
120 | for i, p := range pipes {
121 | configUI := p.GetConfigUI(func() { changed() })
122 | widgets = append(widgets,
123 | g.Button(fmt.Sprintf(" %s ##%d", p.GetName(), i)),
124 | g.Tooltip(p.GetTip()),
125 | buildConfigMenu(i, configUI),
126 | g.Label("->"))
127 | }
128 | }
129 |
130 | widgets = append(widgets, g.Button(" + "), buildPipesMenu())
131 |
132 | return g.Row(widgets...)
133 | }
134 |
135 | func btnLoadClicked() {
136 | dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
137 | dir = filepath.Join(dir, saveDir)
138 |
139 | f, err := os.Open(filepath.Join(dir, comboPreview))
140 | if err != nil {
141 | g.Msgbox("Error", fmt.Sprintf("Load pipeline failed, error message is %s", err.Error()))
142 | return
143 | }
144 | defer f.Close()
145 |
146 | pl, err := pipe.DecodePipeline(f)
147 | if err != nil {
148 | g.Msgbox("Error", fmt.Sprintf("Load pipeline failed, error message is %s", err.Error()))
149 | return
150 | }
151 |
152 | pipeline = *pl
153 | changed()
154 | }
155 |
156 | func btnSaveClicked() {
157 | if len(pipeline) == 0 {
158 | g.Msgbox("Error", "Current pipeline is empty.")
159 | return
160 | }
161 |
162 | g.OpenPopup("Save Pipeline")
163 | }
164 |
165 | func onSave() {
166 | defer func() {
167 | g.CloseCurrentPopup()
168 | loadSavedPiplines()
169 | }()
170 |
171 | if len(savePipelineName) == 0 {
172 | g.Msgbox("Error", "Pipeline's name cannot be empty")
173 | return
174 | }
175 |
176 | // Prepare save dir
177 | dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
178 | dir = filepath.Join(dir, saveDir)
179 |
180 | if _, err := os.Stat(dir); os.IsNotExist(err) {
181 | err := os.Mkdir(dir, os.ModeDir)
182 | if err != nil {
183 | g.Msgbox("Error", fmt.Sprintf("Failed to create save directory, error message is %s", err.Error()))
184 | return
185 | }
186 | }
187 |
188 | saveFilepath := filepath.Join(dir, fmt.Sprintf("%s.pl", savePipelineName))
189 |
190 | buf, err := pipe.EncodePipeline(pipeline)
191 | if err != nil {
192 | g.Msgbox("Error", fmt.Sprintf("Save pipeline failed, error message is %s", err.Error()))
193 | return
194 | }
195 |
196 | err = ioutil.WriteFile(saveFilepath, buf.Bytes(), 0644)
197 | if err != nil {
198 | g.Msgbox("Error", fmt.Sprintf("Save pipeline failed, error message is %s", err.Error()))
199 | return
200 | }
201 | }
202 |
203 | func onCancel() {
204 | g.CloseCurrentPopup()
205 | }
206 |
207 | func onComboChanged() {
208 | comboPreview = savedPipelines[selectedIndex]
209 | }
210 |
211 | func loadSavedPiplines() {
212 | dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
213 | dir = filepath.Join(dir, saveDir)
214 |
215 | // Get all saved *.pl filenames.
216 | var files []string
217 | _ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
218 | if err == nil && !info.IsDir() && filepath.Ext(path) == ".pl" {
219 | files = append(files, filepath.Base(path))
220 | }
221 | return nil
222 | })
223 |
224 | savedPipelines = files
225 | if int(selectedIndex) > len(savedPipelines) {
226 | selectedIndex = 0
227 | }
228 | if len(savedPipelines) > 0 {
229 | comboPreview = savedPipelines[selectedIndex]
230 | }
231 | }
232 |
233 | func loop() {
234 | g.SingleWindow().Layout(g.Layout{
235 | g.SplitLayout(g.DirectionVertical, 300,
236 | g.Layout{
237 | g.Label("Input - input or paste text below"),
238 | g.InputTextMultiline(&input).Size(-1, -1).OnChange(changed),
239 | },
240 | g.Layout{
241 | g.Dummy(0, 8),
242 | g.Row(
243 | g.Label(pipeHint),
244 | g.Combo("##savedPipeines", comboPreview, savedPipelines, &selectedIndex).Size(200).OnChange(onComboChanged),
245 | g.Button("Load").OnClick(btnLoadClicked),
246 | g.Button("Save").OnClick(btnSaveClicked),
247 | ),
248 | g.PopupModal("Save Pipeline").Flags(g.WindowFlagsNoResize).Layout(g.Layout{
249 | g.Label("Enter the name of the pipeline "),
250 | g.InputText(&savePipelineName).Size(200),
251 | g.Row(
252 | g.Button("Save").OnClick(onSave),
253 | g.Button("Cancel").OnClick(onCancel),
254 | ),
255 | }),
256 | buildPipeLineWidgets(pipeline),
257 | g.Dummy(0, 8),
258 | g.Label("Output - output text which is processed by pipeline"),
259 | g.InputTextMultiline(&output).Size(-1, -1).Flags(g.InputTextFlagsReadOnly),
260 | }).Border(false),
261 | g.PrepareMsgbox(),
262 | })
263 | }
264 |
265 | func readStdin() {
266 | stat, err := os.Stdin.Stat()
267 | if err != nil {
268 | return
269 | }
270 |
271 | if (stat.Mode() & os.ModeCharDevice) == 0 {
272 | // Data is being piped to stdin
273 | bytes, _ := ioutil.ReadAll(os.Stdin)
274 | input = string(bytes)
275 | }
276 | }
277 |
278 | func main() {
279 | pipeHint = "Pipeline (click + to add a pipe)"
280 |
281 | // Try to read from stdin if there is anything.
282 | readStdin()
283 |
284 | // Load saved pipelines.
285 | loadSavedPiplines()
286 |
287 | wnd := g.NewMasterWindow("PipeIt", 1024, 768, 0)
288 | wnd.Run(loop)
289 | }
290 |
--------------------------------------------------------------------------------
/pipe/column2row.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 |
6 | g "github.com/AllenDang/giu"
7 | )
8 |
9 | type Column2RowPipe struct{}
10 |
11 | func init() {
12 | gob.Register(&Column2RowPipe{})
13 | }
14 |
15 | func NewColumn2RowPipe() Pipe {
16 | return &Column2RowPipe{}
17 | }
18 |
19 | func (c *Column2RowPipe) GetName() string {
20 | return "C2R"
21 | }
22 |
23 | func (c *Column2RowPipe) GetTip() string {
24 | return "Shift table's column to row"
25 | }
26 |
27 | func (c *Column2RowPipe) GetInputType() DataType {
28 | return DataTypeTable
29 | }
30 |
31 | func (c *Column2RowPipe) GetOutputType() DataType {
32 | return DataTypeTable
33 | }
34 |
35 | func (c *Column2RowPipe) GetConfigUI(changed func()) g.Layout {
36 | return nil
37 | }
38 |
39 | func (c *Column2RowPipe) Process(data interface{}) interface{} {
40 | if table, ok := data.([][]string); ok {
41 | if len(table) > 0 && len(table[0]) > 0 {
42 | columnCount := len(table[0])
43 | rows := make([][]string, columnCount)
44 |
45 | for _, r := range table {
46 | for i, c := range r {
47 | if i < columnCount {
48 | rows[i] = append(rows[i], c)
49 | }
50 | }
51 | }
52 |
53 | return rows
54 | }
55 | }
56 |
57 | return [][]string{[]string{"Error: Column2RowPipe only accepts table as input"}}
58 | }
59 |
--------------------------------------------------------------------------------
/pipe/field.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "strings"
6 |
7 | g "github.com/AllenDang/giu"
8 | )
9 |
10 | type FieldsPipe struct{}
11 |
12 | func init() {
13 | gob.Register(&FieldsPipe{})
14 | }
15 |
16 | func NewFieldsPipe() Pipe {
17 | return &FieldsPipe{}
18 | }
19 |
20 | func (f *FieldsPipe) GetName() string {
21 | return "F"
22 | }
23 |
24 | func (f *FieldsPipe) GetTip() string {
25 | return "Fields splits the string s around each instance of one or more consecutive white space characters"
26 | }
27 |
28 | func (f *FieldsPipe) GetInputType() DataType {
29 | return DataTypeString
30 | }
31 |
32 | func (f *FieldsPipe) GetOutputType() DataType {
33 | return DataTypeStringArray
34 | }
35 |
36 | func (f *FieldsPipe) GetConfigUI(changed func()) g.Layout {
37 | return nil
38 | }
39 |
40 | func (f *FieldsPipe) Process(data interface{}) interface{} {
41 | if str, ok := data.(string); ok {
42 | return strings.Fields(str)
43 | }
44 |
45 | return []string{"Error: Fields only accepts string as input"}
46 | }
47 |
--------------------------------------------------------------------------------
/pipe/fmtrow.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "strings"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type FmtRowPipe struct {
12 | FmtStr string
13 | }
14 |
15 | func init() {
16 | gob.Register(&FmtRowPipe{})
17 | }
18 |
19 | func NewFmtRowPipe() Pipe {
20 | return &FmtRowPipe{
21 | FmtStr: "",
22 | }
23 | }
24 |
25 | func (f *FmtRowPipe) GetName() string {
26 | return "FR"
27 | }
28 |
29 | func (f *FmtRowPipe) GetTip() string {
30 | return "Format row by using %[1]s %[2]s .. %[n]s to reference columns"
31 | }
32 |
33 | func (f *FmtRowPipe) GetInputType() DataType {
34 | return DataTypeTable
35 | }
36 |
37 | func (f *FmtRowPipe) GetOutputType() DataType {
38 | return DataTypeString
39 | }
40 |
41 | func (f *FmtRowPipe) GetConfigUI(changed func()) g.Layout {
42 | return g.Layout{
43 | g.InputText(&(f.FmtStr)).Label("Format string").Size(300).OnChange(changed),
44 | }
45 | }
46 |
47 | func (f *FmtRowPipe) Process(data interface{}) interface{} {
48 | if table, ok := data.([][]string); ok {
49 | var sb strings.Builder
50 |
51 | for _, r := range table {
52 | var tempRow []interface{}
53 | for _, c := range r {
54 | tempRow = append(tempRow, c)
55 | }
56 | sb.WriteString(fmt.Sprintf(f.FmtStr+"\n", tempRow...))
57 | }
58 |
59 | return sb.String()
60 | }
61 |
62 | return "Error: FmtRow only accepts table as input"
63 | }
64 |
--------------------------------------------------------------------------------
/pipe/join.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "strings"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type JoinPipe struct {
12 | JoinWith string
13 | }
14 |
15 | func init() {
16 | gob.Register(&JoinPipe{})
17 | }
18 |
19 | func NewJoinPipe() Pipe {
20 | return &JoinPipe{
21 | JoinWith: ",",
22 | }
23 | }
24 |
25 | func (j *JoinPipe) GetName() string {
26 | return "J"
27 | }
28 |
29 | func (j *JoinPipe) GetTip() string {
30 | return fmt.Sprintf("Join string array with %s", j.JoinWith)
31 | }
32 |
33 | func (j *JoinPipe) GetInputType() DataType {
34 | return DataTypeStringArray
35 | }
36 |
37 | func (j *JoinPipe) GetOutputType() DataType {
38 | return DataTypeString
39 | }
40 |
41 | func (j *JoinPipe) GetConfigUI(changed func()) g.Layout {
42 | return g.Layout{
43 | g.InputText(&(j.JoinWith)).Label("Join With").Size(100).OnChange(changed),
44 | }
45 | }
46 |
47 | func (j *JoinPipe) Process(data interface{}) interface{} {
48 | if strs, ok := data.([]string); ok {
49 | return strings.Join(strs, j.JoinWith)
50 | }
51 |
52 | return "Error: Join only accepts string array as input"
53 | }
54 |
--------------------------------------------------------------------------------
/pipe/line.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "strings"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type LinePipe struct{}
12 |
13 | func init() {
14 | gob.Register(&LinePipe{})
15 | }
16 |
17 | func NewLinePipe() Pipe {
18 | return &LinePipe{}
19 | }
20 |
21 | func (l *LinePipe) GetName() string {
22 | return "L"
23 | }
24 |
25 | func (l *LinePipe) GetTip() string {
26 | return "Output input string line by line"
27 | }
28 |
29 | func (l *LinePipe) GetInputType() DataType {
30 | return DataTypeStringArray
31 | }
32 |
33 | func (l *LinePipe) GetOutputType() DataType {
34 | return DataTypeString
35 | }
36 |
37 | func (l *LinePipe) GetConfigUI(changed func()) g.Layout {
38 | return nil
39 | }
40 |
41 | func (l *LinePipe) Process(data interface{}) interface{} {
42 | if strs, ok := data.([]string); ok {
43 | var sb strings.Builder
44 | for _, s := range strs {
45 | sb.WriteString(fmt.Sprintf("%s\n", s))
46 | }
47 |
48 | return sb.String()
49 | }
50 |
51 | return "Error: Line only accepts string array as input"
52 | }
53 |
--------------------------------------------------------------------------------
/pipe/match.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "regexp"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type MatchPipe struct {
12 | MatchWith string
13 | }
14 |
15 | func init() {
16 | gob.Register(&MatchPipe{})
17 | }
18 |
19 | func NewMatchPipe() Pipe {
20 | return &MatchPipe{}
21 | }
22 |
23 | func (m *MatchPipe) GetName() string {
24 | return "M"
25 | }
26 |
27 | func (m *MatchPipe) GetTip() string {
28 | return fmt.Sprintf("Match input string array with regex %s", m.MatchWith)
29 | }
30 |
31 | func (m *MatchPipe) GetInputType() DataType {
32 | return DataTypeStringArray
33 | }
34 |
35 | func (m *MatchPipe) GetOutputType() DataType {
36 | return DataTypeStringArray
37 | }
38 |
39 | func (m *MatchPipe) GetConfigUI(changed func()) g.Layout {
40 | return g.Layout{
41 | g.InputText(&(m.MatchWith)).Label("Match with").Size(100).OnChange(changed),
42 | }
43 | }
44 |
45 | func (m *MatchPipe) Process(data interface{}) interface{} {
46 | if strs, ok := data.([]string); ok {
47 | var result []string
48 | for _, s := range strs {
49 | if matched, _ := regexp.MatchString(m.MatchWith, s); matched {
50 | result = append(result, s)
51 | }
52 | }
53 |
54 | return result
55 | }
56 |
57 | return []string{"Error: Match only accepts string array as input"}
58 | }
59 |
--------------------------------------------------------------------------------
/pipe/pipe.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "bytes"
5 | "encoding/gob"
6 | "io"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type DataType int
12 |
13 | const (
14 | DataTypeString DataType = iota
15 | DataTypeStringArray
16 | DataTypeTable
17 | )
18 |
19 | type Parameter struct {
20 | Type DataType
21 | Value interface{}
22 | }
23 |
24 | type Pipe interface {
25 | // Get information for the pipe including name, bgColor, nameColor and borderColor
26 | GetName() string
27 | GetTip() string
28 | GetInputType() DataType
29 | GetOutputType() DataType
30 | GetConfigUI(changed func()) g.Layout
31 | Process(data interface{}) interface{}
32 | }
33 |
34 | type Pipeline []Pipe
35 |
36 | func EncodePipeline(pl Pipeline) (*bytes.Buffer, error) {
37 | var buf bytes.Buffer
38 | enc := gob.NewEncoder(&buf)
39 | err := enc.Encode(&pl)
40 | if err != nil {
41 | return nil, err
42 | }
43 |
44 | return &buf, nil
45 | }
46 |
47 | func DecodePipeline(r io.Reader) (*Pipeline, error) {
48 | var pl Pipeline
49 | dec := gob.NewDecoder(r)
50 | err := dec.Decode(&pl)
51 | if err != nil {
52 | return nil, err
53 | }
54 |
55 | return &pl, nil
56 | }
57 |
--------------------------------------------------------------------------------
/pipe/registry.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | type PipeBuilder struct {
4 | Name string
5 | Tip string
6 | Builder func() Pipe
7 | }
8 |
9 | var (
10 | pipeRegistry map[DataType][]*PipeBuilder
11 | )
12 |
13 | func init() {
14 | pipeRegistry = make(map[DataType][]*PipeBuilder)
15 | pipeRegistry[DataTypeString] = []*PipeBuilder{
16 | &PipeBuilder{"Split", "Split input string into string array using regexp expression", NewRegexpSplitPipe},
17 | &PipeBuilder{"Fields", "Fields splits the string s around each instance of one or more consecutive white space characters", NewFieldsPipe},
18 | &PipeBuilder{"Table", "Table parse input string to rows and columns", NewTablePipe},
19 | }
20 | pipeRegistry[DataTypeStringArray] = []*PipeBuilder{
21 | &PipeBuilder{"Join", "Join input string array with given separator", NewJoinPipe},
22 | &PipeBuilder{"Match", "Match input string array with given regex", NewMatchPipe},
23 | &PipeBuilder{"Surround", "Add prefix and suffix to each element of input string array", NewSurroundPipe},
24 | &PipeBuilder{"Replace", "Search and replace for each element of input string array", NewReplacePipe},
25 | &PipeBuilder{"Line", "Output input string array line by line", NewLinePipe},
26 | &PipeBuilder{"Trim", "Trim returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed", NewTrimPipe},
27 | }
28 | pipeRegistry[DataTypeTable] = []*PipeBuilder{
29 | &PipeBuilder{"Column2Row", "Shift table's column to row", NewColumn2RowPipe},
30 | &PipeBuilder{"FmtRow", "Format row to string", NewFmtRowPipe},
31 | }
32 | }
33 |
34 | func QueryPipes(byType DataType) []*PipeBuilder {
35 | if v, ok := pipeRegistry[byType]; ok {
36 | return v
37 | }
38 |
39 | return nil
40 | }
41 |
42 | func QueryPipesBetween(inType, outType DataType) []*PipeBuilder {
43 | if inPipes, ok := pipeRegistry[inType]; ok {
44 | var pipes []*PipeBuilder
45 | for _, p := range inPipes {
46 | if p.Builder().GetOutputType() == outType {
47 | pipes = append(pipes, p)
48 | }
49 | }
50 | return pipes
51 | }
52 |
53 | return nil
54 | }
55 |
--------------------------------------------------------------------------------
/pipe/replace.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "regexp"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type ReplacePipe struct {
12 | Replace string
13 | With string
14 | }
15 |
16 | func init() {
17 | gob.Register(&ReplacePipe{})
18 | }
19 |
20 | func NewReplacePipe() Pipe {
21 | return &ReplacePipe{}
22 | }
23 |
24 | func (r *ReplacePipe) GetName() string {
25 | return "R"
26 | }
27 |
28 | func (r *ReplacePipe) GetTip() string {
29 | return fmt.Sprintf("Replace each string of input string array from %s to %s", r.Replace, r.With)
30 | }
31 |
32 | func (r *ReplacePipe) GetInputType() DataType {
33 | return DataTypeStringArray
34 | }
35 |
36 | func (r *ReplacePipe) GetOutputType() DataType {
37 | return DataTypeStringArray
38 | }
39 |
40 | func (r *ReplacePipe) GetConfigUI(changed func()) g.Layout {
41 | return g.Layout{
42 | g.InputText(&(r.Replace)).Label("Replace").Size(100).OnChange(changed),
43 | g.InputText(&(r.With)).Label("With").Size(100).OnChange(changed),
44 | }
45 | }
46 |
47 | func (r *ReplacePipe) Process(data interface{}) interface{} {
48 | if strs, ok := data.([]string); ok {
49 | re, err := regexp.Compile(r.Replace)
50 | if err != nil {
51 | return []string{"Error: Invalid regex"}
52 | }
53 |
54 | var result []string
55 | for _, s := range strs {
56 | result = append(result, re.ReplaceAllString(s, r.With))
57 | }
58 |
59 | return result
60 | }
61 |
62 | return []string{"Error: Replace only accepts string array as input"}
63 | }
64 |
--------------------------------------------------------------------------------
/pipe/rsplit.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "regexp"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type RegexpSplitPipe struct {
12 | SplitWith string
13 | }
14 |
15 | func init() {
16 | gob.Register(&RegexpSplitPipe{})
17 | }
18 |
19 | func NewRegexpSplitPipe() Pipe {
20 | return &RegexpSplitPipe{
21 | SplitWith: ",",
22 | }
23 | }
24 |
25 | func (r *RegexpSplitPipe) GetName() string {
26 | return "S"
27 | }
28 |
29 | func (r *RegexpSplitPipe) GetTip() string {
30 | return fmt.Sprintf("Split input string with regexp: %s", r.SplitWith)
31 | }
32 |
33 | func (r *RegexpSplitPipe) GetInputType() DataType {
34 | return DataTypeString
35 | }
36 |
37 | func (r *RegexpSplitPipe) GetOutputType() DataType {
38 | return DataTypeStringArray
39 | }
40 |
41 | func (r *RegexpSplitPipe) GetConfigUI(changed func()) g.Layout {
42 | return g.Layout{
43 | g.InputText(&(r.SplitWith)).Label("Split").Size(100).OnChange(changed),
44 | }
45 | }
46 |
47 | func (r *RegexpSplitPipe) Process(data interface{}) interface{} {
48 | if str, ok := data.(string); ok {
49 | re, err := regexp.Compile(r.SplitWith)
50 | if err == nil {
51 | return re.Split(str, -1)
52 | } else {
53 | return []string{err.Error()}
54 | }
55 | }
56 |
57 | return []string{"Error: RegexpSplit only accepts string as input"}
58 | }
59 |
--------------------------------------------------------------------------------
/pipe/surround.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "strings"
7 |
8 | g "github.com/AllenDang/giu"
9 | )
10 |
11 | type SurroundPipe struct {
12 | Prefix string
13 | Suffix string
14 | }
15 |
16 | func init() {
17 | gob.Register(&SurroundPipe{})
18 | }
19 |
20 | func NewSurroundPipe() Pipe {
21 | return &SurroundPipe{
22 | Prefix: "'",
23 | Suffix: "'",
24 | }
25 | }
26 |
27 | func (p *SurroundPipe) GetName() string {
28 | return "SR"
29 | }
30 |
31 | func (p *SurroundPipe) GetTip() string {
32 | return fmt.Sprintf("Surround each string of input string array with %s as Prefix and %s as Suffix", p.Prefix, p.Suffix)
33 | }
34 |
35 | func (p *SurroundPipe) GetInputType() DataType {
36 | return DataTypeStringArray
37 | }
38 |
39 | func (p *SurroundPipe) GetOutputType() DataType {
40 | return DataTypeStringArray
41 | }
42 |
43 | func (p *SurroundPipe) GetConfigUI(changed func()) g.Layout {
44 | return g.Layout{
45 | g.Label("Use %d to generate series number"),
46 | g.InputText(&(p.Prefix)).Label("Prefix").Size(100).OnChange(changed),
47 | g.InputText(&(p.Suffix)).Label("Suffix").Size(100).OnChange(changed),
48 | }
49 | }
50 |
51 | func (p *SurroundPipe) Process(data interface{}) interface{} {
52 | if strs, ok := data.([]string); ok {
53 | var result []string
54 | for i, s := range strs {
55 | pf := strings.Replace(p.Prefix, "%d", fmt.Sprintf("%d", i+1), -1)
56 | sf := strings.Replace(p.Suffix, "%d", fmt.Sprintf("%d", i+1), -1)
57 | result = append(result, fmt.Sprintf("%s%s%s", pf, s, sf))
58 | }
59 |
60 | return result
61 | }
62 |
63 | return []string{"Error: Surround only accepts string array as input"}
64 | }
65 |
--------------------------------------------------------------------------------
/pipe/table.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "regexp"
6 |
7 | g "github.com/AllenDang/giu"
8 | )
9 |
10 | type TablePipe struct {
11 | SplitRowWith string
12 | SplitColumnWith string
13 | }
14 |
15 | func init() {
16 | gob.Register(&TablePipe{})
17 | }
18 |
19 | func NewTablePipe() Pipe {
20 | return &TablePipe{
21 | SplitRowWith: "\n",
22 | SplitColumnWith: ",",
23 | }
24 | }
25 |
26 | func (t *TablePipe) GetName() string {
27 | return "T"
28 | }
29 |
30 | func (t *TablePipe) GetTip() string {
31 | return "Table parse input string to rows and columns"
32 | }
33 |
34 | func (t *TablePipe) GetInputType() DataType {
35 | return DataTypeString
36 | }
37 |
38 | func (t *TablePipe) GetOutputType() DataType {
39 | return DataTypeTable
40 | }
41 |
42 | func (t *TablePipe) GetConfigUI(changed func()) g.Layout {
43 | return g.Layout{
44 | g.InputText(&(t.SplitRowWith)).Label("Split row with").Size(100).OnChange(changed),
45 | g.InputText(&(t.SplitColumnWith)).Label("Split column with").Size(100).OnChange(changed),
46 | }
47 | }
48 |
49 | func (t *TablePipe) Process(data interface{}) interface{} {
50 | if str, ok := data.(string); ok {
51 | re, err := regexp.Compile(t.SplitRowWith)
52 | if err != nil {
53 | return [][]string{[]string{err.Error()}}
54 | }
55 |
56 | ce, err := regexp.Compile(t.SplitColumnWith)
57 | if err != nil {
58 | return [][]string{[]string{err.Error()}}
59 | }
60 |
61 | tempRows := re.Split(str, -1)
62 |
63 | var rows [][]string
64 |
65 | for _, r := range tempRows {
66 | rows = append(rows, ce.Split(r, -1))
67 | }
68 |
69 | return rows
70 | }
71 |
72 | return [][]string{[]string{"Error: Table only accepts string as input"}}
73 | }
74 |
--------------------------------------------------------------------------------
/pipe/trim.go:
--------------------------------------------------------------------------------
1 | package pipe
2 |
3 | import (
4 | "encoding/gob"
5 | "strings"
6 |
7 | g "github.com/AllenDang/giu"
8 | )
9 |
10 | type TrimPipe struct {
11 | TrimWith string
12 | }
13 |
14 | func init() {
15 | gob.Register(&TrimPipe{})
16 | }
17 |
18 | func NewTrimPipe() Pipe {
19 | return &TrimPipe{}
20 | }
21 |
22 | func (t *TrimPipe) GetName() string {
23 | return "T"
24 | }
25 |
26 | func (t *TrimPipe) GetTip() string {
27 | return "Trim returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed"
28 | }
29 |
30 | func (t *TrimPipe) GetInputType() DataType {
31 | return DataTypeStringArray
32 | }
33 |
34 | func (t *TrimPipe) GetOutputType() DataType {
35 | return DataTypeStringArray
36 | }
37 |
38 | func (t *TrimPipe) GetConfigUI(changed func()) g.Layout {
39 | return g.Layout{
40 | g.InputText(&(t.TrimWith)).Label("Trim with").Size(100).OnChange(changed),
41 | }
42 | }
43 |
44 | func (t *TrimPipe) Process(data interface{}) interface{} {
45 | if strs, ok := data.([]string); ok {
46 | var results []string
47 | for _, s := range strs {
48 | results = append(results, strings.Trim(s, t.TrimWith))
49 | }
50 |
51 | return results
52 | }
53 |
54 | return []string{"Error: Trim only accepts string array as input"}
55 | }
56 |
--------------------------------------------------------------------------------
/resource/pipeline.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/resource/pipeline.icns
--------------------------------------------------------------------------------
/resource/pipeline.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/resource/pipeline.ico
--------------------------------------------------------------------------------
/resource/pipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/resource/pipeline.png
--------------------------------------------------------------------------------
/screenshot/addquotation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/screenshot/addquotation.gif
--------------------------------------------------------------------------------
/screenshot/commatolines.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/screenshot/commatolines.gif
--------------------------------------------------------------------------------
/screenshot/findimageurl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/screenshot/findimageurl.gif
--------------------------------------------------------------------------------
/screenshot/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenDang/PipeIt/849da234d858308326e4beb872b0e25de418080c/screenshot/screenshot1.png
--------------------------------------------------------------------------------