]> git.lizzy.rs Git - micro.git/blob - cmd/micro/util.go
4dc2fddeef1ea59fce6dec715a68b9dcd18b8fba
[micro.git] / cmd / micro / util.go
1 package main
2
3 import (
4         "os"
5         "path/filepath"
6         "strconv"
7         "strings"
8         "time"
9         "unicode/utf8"
10
11         "github.com/mattn/go-runewidth"
12 )
13
14 // Util.go is a collection of utility functions that are used throughout
15 // the program
16
17 // Count returns the length of a string in runes
18 // This is exactly equivalent to utf8.RuneCountInString(), just less characters
19 func Count(s string) int {
20         return utf8.RuneCountInString(s)
21 }
22
23 // NumOccurences counts the number of occurences of a byte in a string
24 func NumOccurences(s string, c byte) int {
25         var n int
26         for i := 0; i < len(s); i++ {
27                 if s[i] == c {
28                         n++
29                 }
30         }
31         return n
32 }
33
34 // Spaces returns a string with n spaces
35 func Spaces(n int) string {
36         var str string
37         for i := 0; i < n; i++ {
38                 str += " "
39         }
40         return str
41 }
42
43 // Min takes the min of two ints
44 func Min(a, b int) int {
45         if a > b {
46                 return b
47         }
48         return a
49 }
50
51 // Max takes the max of two ints
52 func Max(a, b int) int {
53         if a > b {
54                 return a
55         }
56         return b
57 }
58
59 // IsWordChar returns whether or not the string is a 'word character'
60 // If it is a unicode character, then it does not match
61 // Word characters are defined as [A-Za-z0-9_]
62 func IsWordChar(str string) bool {
63         if len(str) > 1 {
64                 // Unicode
65                 return false
66         }
67         c := str[0]
68         return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')
69 }
70
71 // IsWhitespace returns true if the given rune is a space, tab, or newline
72 func IsWhitespace(c rune) bool {
73         return c == ' ' || c == '\t' || c == '\n'
74 }
75
76 // Contains returns whether or not a string array contains a given string
77 func Contains(list []string, a string) bool {
78         for _, b := range list {
79                 if b == a {
80                         return true
81                 }
82         }
83         return false
84 }
85
86 // Insert makes a simple insert into a string at the given position
87 func Insert(str string, pos int, value string) string {
88         return string([]rune(str)[:pos]) + value + string([]rune(str)[pos:])
89 }
90
91 // GetLeadingWhitespace returns the leading whitespace of the given string
92 func GetLeadingWhitespace(str string) string {
93         ws := ""
94         for _, c := range str {
95                 if c == ' ' || c == '\t' {
96                         ws += string(c)
97                 } else {
98                         break
99                 }
100         }
101         return ws
102 }
103
104 // IsSpaces checks if a given string is only spaces
105 func IsSpaces(str string) bool {
106         for _, c := range str {
107                 if c != ' ' {
108                         return false
109                 }
110         }
111
112         return true
113 }
114
115 // IsSpacesOrTabs checks if a given string contains only spaces and tabs
116 func IsSpacesOrTabs(str string) bool {
117         for _, c := range str {
118                 if c != ' ' && c != '\t' {
119                         return false
120                 }
121         }
122
123         return true
124 }
125
126 // ParseBool is almost exactly like strconv.ParseBool, except it also accepts 'on' and 'off'
127 // as 'true' and 'false' respectively
128 func ParseBool(str string) (bool, error) {
129         if str == "on" {
130                 return true, nil
131         }
132         if str == "off" {
133                 return false, nil
134         }
135         return strconv.ParseBool(str)
136 }
137
138 // EscapePath replaces every path separator in a given path with a %
139 func EscapePath(path string) string {
140         path = filepath.ToSlash(path)
141         return strings.Replace(path, "/", "%", -1)
142 }
143
144 // GetModTime returns the last modification time for a given file
145 // It also returns a boolean if there was a problem accessing the file
146 func GetModTime(path string) (time.Time, bool) {
147         info, err := os.Stat(path)
148         if err != nil {
149                 return time.Now(), false
150         }
151         return info.ModTime(), true
152 }
153
154 // StringWidth returns the width of a string where tabs count as `tabsize` width
155 func StringWidth(str string, tabsize int) int {
156         sw := runewidth.StringWidth(str)
157         sw += NumOccurences(str, '\t') * (tabsize - 1)
158         return sw
159 }
160
161 // WidthOfLargeRunes searches all the runes in a string and counts up all the widths of runes
162 // that have a width larger than 1 (this also counts tabs as `tabsize` width)
163 func WidthOfLargeRunes(str string, tabsize int) int {
164         count := 0
165         for _, ch := range str {
166                 var w int
167                 if ch == '\t' {
168                         w = tabsize
169                 } else {
170                         w = runewidth.RuneWidth(ch)
171                 }
172                 if w > 1 {
173                         count += (w - 1)
174                 }
175         }
176         return count
177 }
178
179 // RunePos returns the rune index of a given byte index
180 // This could cause problems if the byte index is between code points
181 func runePos(p int, str string) int {
182         return utf8.RuneCountInString(str[:p])
183 }
184
185 func lcs(a, b string) string {
186         arunes := []rune(a)
187         brunes := []rune(b)
188
189         lcs := ""
190         for i, r := range arunes {
191                 if i >= len(brunes) {
192                         break
193                 }
194                 if r == brunes[i] {
195                         lcs += string(r)
196                 } else {
197                         break
198                 }
199         }
200         return lcs
201 }
202
203 func CommonSubstring(arr ...string) string {
204         commonStr := arr[0]
205
206         for _, str := range arr[1:] {
207                 commonStr = lcs(commonStr, str)
208         }
209
210         return commonStr
211 }
212
213 // Abs is a simple absolute value function for ints
214 func Abs(n int) int {
215         if n < 0 {
216                 return -n
217         }
218         return n
219 }