-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathclipboard.go
143 lines (112 loc) · 3.04 KB
/
clipboard.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
134
135
136
137
138
139
140
141
142
143
// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.
package commands
import (
"sort"
"strings"
"github.com/limetext/backend"
"github.com/limetext/text"
)
type (
// Copy copies the current selection to the clipboard. If there
// are multiple selections, they are concatenated in order from
// top to bottom of the file, separated by newlines
Copy struct {
backend.DefaultCommand
}
// Cut copies the current selection to the clipboard, removing it from the
// buffer. If there are multiple selections, they are concatenated in order
// from top to bottom of the file, separated by newlines.
Cut struct {
backend.DefaultCommand
}
// Paste pastes the contents of the clipboard, overwriting the current
// selection, if any. If there are multiple selections, the clipboard is
// split into lines. If the number of lines equals the number of selections,
// the lines are pasted separately into each selection in order from top to
// bottom of the file. Otherwise the entire clipboard is pasted over every
// selection.
Paste struct {
backend.DefaultCommand
}
)
func getRegions(v *backend.View, cut bool) *text.RegionSet {
rs := &text.RegionSet{}
regions := v.Sel().Regions()
sort.Sort(regionSorter(regions))
rs.AddAll(regions)
he, ae := rs.HasEmpty(), !rs.HasNonEmpty() || cut
for _, r := range rs.Regions() {
if ae && r.Empty() {
rs.Add(v.FullLineR(r))
} else if he && r.Empty() {
rs.Subtract(r)
}
}
return rs
}
func getSelForCopy(v *backend.View, rs *text.RegionSet) (s string, ex bool) {
ss := make([]string, rs.Len())
for i, r := range rs.Regions() {
sub := v.Substr(r)
if !v.Sel().HasNonEmpty() && !strings.HasSuffix(sub, "\n") {
sub += "\n"
ex = true
}
ss[i] = sub
}
s = strings.Join(ss, "\n")
return
}
// Run executes the Copy command.
func (c *Copy) Run(v *backend.View, e *backend.Edit) error {
rs := getRegions(v, false)
s, ex := getSelForCopy(v, rs)
cb := backend.GetEditor().Clipboard()
cb.Set(s, ex)
return nil
}
// Run executes the Cut command.
func (c *Cut) Run(v *backend.View, e *backend.Edit) error {
s, ex := getSelForCopy(v, getRegions(v, false))
rs := getRegions(v, true)
regions := rs.Regions()
sort.Sort(sort.Reverse(regionSorter(regions)))
for _, r := range regions {
v.Erase(e, r)
}
cb := backend.GetEditor().Clipboard()
cb.Set(s, ex)
return nil
}
// Run executes the Paste command.
func (c *Paste) Run(v *backend.View, e *backend.Edit) error {
cb := backend.GetEditor().Clipboard()
rs := &text.RegionSet{}
regions := v.Sel().Regions()
sort.Sort(regionSorter(regions))
rs.AddAll(regions)
s, ex := cb.Get()
ss := strings.Split(s, "\n")
split := !ex && len(ss) == rs.Len()
for i := rs.Len() - 1; i >= 0; i-- {
r := rs.Get(i)
if split {
v.Replace(e, r, ss[i])
} else if !ex {
v.Replace(e, r, s)
} else {
l := v.FullLineR(r)
v.Insert(e, l.Begin(), s)
}
}
return nil
}
func init() {
register([]backend.Command{
&Copy{},
&Cut{},
&Paste{},
})
}