Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
orangecat
ollama
Commits
89d99001
Unverified
Commit
89d99001
authored
Jun 04, 2024
by
Michael Yang
Committed by
GitHub
Jun 04, 2024
Browse files
Merge pull request #4570 from ollama/mxyng/slices
lint some of the things
parents
4a048715
6297f856
Changes
54
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
64 additions
and
78 deletions
+64
-78
convert/torch.go
convert/torch.go
+1
-2
envconfig/config.go
envconfig/config.go
+4
-3
format/format_test.go
format/format_test.go
+0
-1
gpu/amd_windows.go
gpu/amd_windows.go
+1
-1
gpu/assets.go
gpu/assets.go
+1
-1
gpu/cuda_common.go
gpu/cuda_common.go
+0
-1
gpu/gpu.go
gpu/gpu.go
+3
-3
gpu/gpu_test.go
gpu/gpu_test.go
+3
-2
llm/gguf.go
llm/gguf.go
+4
-4
llm/memory.go
llm/memory.go
+2
-2
llm/payload.go
llm/payload.go
+1
-1
llm/server.go
llm/server.go
+9
-9
openai/openai.go
openai/openai.go
+0
-1
parser/parser_test.go
parser/parser_test.go
+15
-16
progress/progress.go
progress/progress.go
+2
-2
readline/buffer.go
readline/buffer.go
+7
-17
readline/history.go
readline/history.go
+2
-2
readline/readline.go
readline/readline.go
+7
-8
readline/readline_unix.go
readline/readline_unix.go
+1
-1
readline/readline_windows.go
readline/readline_windows.go
+1
-1
No files found.
convert/torch.go
View file @
89d99001
...
...
@@ -88,7 +88,7 @@ func (tf *TorchFormat) GetTensors(dirpath string, params *Params) ([]llm.Tensor,
Name
:
ggufName
,
Kind
:
kind
,
Offset
:
offset
,
// calculate the offset
Shape
:
shape
[
:
]
,
Shape
:
shape
,
}
tensor
.
WriterTo
=
torchWriterTo
{
...
...
@@ -104,7 +104,6 @@ func (tf *TorchFormat) GetTensors(dirpath string, params *Params) ([]llm.Tensor,
}
return
tensors
,
nil
}
func
getAltParams
(
dirpath
string
)
(
*
Params
,
error
)
{
...
...
envconfig/config.go
View file @
89d99001
...
...
@@ -3,6 +3,7 @@ package envconfig
import
(
"fmt"
"log/slog"
"net"
"os"
"path/filepath"
"runtime"
...
...
@@ -126,7 +127,7 @@ func LoadConfig() {
var
paths
[]
string
for
_
,
root
:=
range
[]
string
{
filepath
.
Dir
(
appExe
),
cwd
}
{
paths
=
append
(
paths
,
filepath
.
Join
(
root
)
,
root
,
filepath
.
Join
(
root
,
"windows-"
+
runtime
.
GOARCH
),
filepath
.
Join
(
root
,
"dist"
,
"windows-"
+
runtime
.
GOARCH
),
)
...
...
@@ -184,8 +185,8 @@ func LoadConfig() {
AllowOrigins
=
append
(
AllowOrigins
,
fmt
.
Sprintf
(
"http://%s"
,
allowOrigin
),
fmt
.
Sprintf
(
"https://%s"
,
allowOrigin
),
fmt
.
Sprintf
(
"http://%s
:*
"
,
allowOrigin
),
fmt
.
Sprintf
(
"https://%s
:*
"
,
allowOrigin
),
fmt
.
Sprintf
(
"http://%s"
,
net
.
JoinHostPort
(
allowOrigin
,
"*"
)
),
fmt
.
Sprintf
(
"https://%s"
,
net
.
JoinHostPort
(
allowOrigin
,
"*"
)
),
)
}
...
...
format/format_test.go
View file @
89d99001
...
...
@@ -5,7 +5,6 @@ import (
)
func
TestHumanNumber
(
t
*
testing
.
T
)
{
type
testCase
struct
{
input
uint64
expected
string
...
...
gpu/amd_windows.go
View file @
89d99001
...
...
@@ -65,7 +65,7 @@ func AMDGetGPUInfo() []GpuInfo {
slog
.
Debug
(
"detected hip devices"
,
"count"
,
count
)
// TODO how to determine the underlying device ID when visible devices is causing this to subset?
for
i
:=
0
;
i
<
count
;
i
++
{
for
i
:=
range
count
{
err
=
hl
.
HipSetDevice
(
i
)
if
err
!=
nil
{
slog
.
Warn
(
"set device"
,
"id"
,
i
,
"error"
,
err
)
...
...
gpu/assets.go
View file @
89d99001
...
...
@@ -80,7 +80,7 @@ func cleanupTmpDirs() {
if
err
==
nil
{
pid
,
err
:=
strconv
.
Atoi
(
string
(
raw
))
if
err
==
nil
{
if
proc
,
err
:=
os
.
FindProcess
(
int
(
pid
)
)
;
err
==
nil
&&
!
errors
.
Is
(
proc
.
Signal
(
syscall
.
Signal
(
0
)),
os
.
ErrProcessDone
)
{
if
proc
,
err
:=
os
.
FindProcess
(
pid
);
err
==
nil
&&
!
errors
.
Is
(
proc
.
Signal
(
syscall
.
Signal
(
0
)),
os
.
ErrProcessDone
)
{
// Another running ollama, ignore this tmpdir
continue
}
...
...
gpu/cuda_common.go
View file @
89d99001
...
...
@@ -18,5 +18,4 @@ func cudaGetVisibleDevicesEnv(gpuInfo []GpuInfo) (string, string) {
ids
=
append
(
ids
,
info
.
ID
)
}
return
"CUDA_VISIBLE_DEVICES"
,
strings
.
Join
(
ids
,
","
)
}
gpu/gpu.go
View file @
89d99001
...
...
@@ -187,7 +187,7 @@ func GetGPUInfo() GpuInfoList {
resp
:=
[]
GpuInfo
{}
// NVIDIA first
for
i
:=
0
;
i
<
gpuHandles
.
deviceCount
;
i
++
{
for
i
:=
range
gpuHandles
.
deviceCount
{
// TODO once we support CPU compilation variants of GPU libraries refine this...
if
cpuVariant
==
""
&&
runtime
.
GOARCH
==
"amd64"
{
continue
...
...
@@ -221,8 +221,8 @@ func GetGPUInfo() GpuInfoList {
gpuInfo
.
MinimumMemory
=
cudaMinimumMemory
gpuInfo
.
DependencyPath
=
depPath
gpuInfo
.
Name
=
C
.
GoString
(
&
memInfo
.
gpu_name
[
0
])
gpuInfo
.
DriverMajor
=
int
(
driverMajor
)
gpuInfo
.
DriverMinor
=
int
(
driverMinor
)
gpuInfo
.
DriverMajor
=
driverMajor
gpuInfo
.
DriverMinor
=
driverMinor
// TODO potentially sort on our own algorithm instead of what the underlying GPU library does...
resp
=
append
(
resp
,
gpuInfo
)
...
...
gpu/gpu_test.go
View file @
89d99001
...
...
@@ -5,11 +5,12 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func
TestBasicGetGPUInfo
(
t
*
testing
.
T
)
{
info
:=
GetGPUInfo
()
assert
.
Greater
(
t
,
len
(
info
)
,
0
)
assert
.
NotEmpty
(
t
,
len
(
info
))
assert
.
Contains
(
t
,
"cuda rocm cpu metal"
,
info
[
0
]
.
Library
)
if
info
[
0
]
.
Library
!=
"cpu"
{
assert
.
Greater
(
t
,
info
[
0
]
.
TotalMemory
,
uint64
(
0
))
...
...
@@ -19,7 +20,7 @@ func TestBasicGetGPUInfo(t *testing.T) {
func
TestCPUMemInfo
(
t
*
testing
.
T
)
{
info
,
err
:=
GetCPUMem
()
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
switch
runtime
.
GOOS
{
case
"darwin"
:
t
.
Skip
(
"CPU memory not populated on darwin"
)
...
...
llm/gguf.go
View file @
89d99001
...
...
@@ -592,8 +592,8 @@ func (llm *gguf) Encode(ws io.WriteSeeker, kv KV, tensors []Tensor) error {
return
err
}
dims
:=
0
for
cnt
:=
0
;
cnt
<
len
(
tensor
.
Shape
)
;
cnt
++
{
var
dims
int
for
cnt
:=
range
len
(
tensor
.
Shape
)
{
if
tensor
.
Shape
[
cnt
]
>
0
{
dims
++
}
...
...
@@ -603,8 +603,8 @@ func (llm *gguf) Encode(ws io.WriteSeeker, kv KV, tensors []Tensor) error {
return
err
}
for
i
:=
0
;
i
<
dims
;
i
++
{
if
err
:=
binary
.
Write
(
ws
,
llm
.
ByteOrder
,
uint64
(
tensor
.
Shape
[
dims
-
1
-
i
])
)
;
err
!=
nil
{
for
i
:=
range
dims
{
if
err
:=
binary
.
Write
(
ws
,
llm
.
ByteOrder
,
tensor
.
Shape
[
dims
-
1
-
i
]);
err
!=
nil
{
return
err
}
}
...
...
llm/memory.go
View file @
89d99001
...
...
@@ -5,9 +5,9 @@ import (
"log/slog"
"github.com/ollama/ollama/api"
"github.com/ollama/ollama/envconfig"
"github.com/ollama/ollama/format"
"github.com/ollama/ollama/gpu"
"github.com/ollama/ollama/envconfig"
)
// This algorithm looks for a complete fit to determine if we need to unload other models
...
...
@@ -103,7 +103,7 @@ func EstimateGPULayers(gpus []gpu.GpuInfo, ggml *GGML, projectors []string, opts
}
var
layerCount
int
for
i
:=
0
;
i
<
int
(
ggml
.
KV
()
.
BlockCount
())
;
i
++
{
for
i
:=
range
int
(
ggml
.
KV
()
.
BlockCount
())
{
if
blk
,
ok
:=
layers
[
fmt
.
Sprintf
(
"blk.%d"
,
i
)];
ok
{
memoryLayer
:=
blk
.
size
()
...
...
llm/payload.go
View file @
89d99001
...
...
@@ -10,9 +10,9 @@ import (
"os"
"path/filepath"
"runtime"
"slices"
"strings"
"golang.org/x/exp/slices"
"golang.org/x/sync/errgroup"
"github.com/ollama/ollama/gpu"
...
...
llm/server.go
View file @
89d99001
...
...
@@ -85,7 +85,6 @@ func NewLlamaServer(gpus gpu.GpuInfoList, model string, ggml *GGML, adapters, pr
var
systemMemory
uint64
gpuCount
:=
len
(
gpus
)
if
(
len
(
gpus
)
==
1
&&
gpus
[
0
]
.
Library
==
"cpu"
)
||
opts
.
NumGPU
==
0
{
// TODO evaluate system memory to see if we should block the load, or force an unload of another CPU runner
cpuRunner
=
serverForCpu
()
...
...
@@ -104,21 +103,22 @@ func NewLlamaServer(gpus gpu.GpuInfoList, model string, ggml *GGML, adapters, pr
var
layers
int
layers
,
estimatedVRAM
,
estimatedTotal
=
EstimateGPULayers
(
gpus
,
ggml
,
projectors
,
opts
)
if
gpus
[
0
]
.
Library
==
"metal"
&&
estimatedVRAM
>
systemMemory
{
switch
{
case
gpus
[
0
]
.
Library
==
"metal"
&&
estimatedVRAM
>
systemMemory
:
// disable partial offloading when model is greater than total system memory as this
// can lead to locking up the system
opts
.
NumGPU
=
0
}
else
if
gpus
[
0
]
.
Library
!=
"metal"
&&
layers
==
0
{
case
gpus
[
0
]
.
Library
!=
"metal"
&&
layers
==
0
:
// Don't bother loading into the GPU if no layers can fit
cpuRunner
=
serverForCpu
()
gpuCount
=
0
}
else
if
opts
.
NumGPU
<
0
&&
layers
>
0
&&
gpus
[
0
]
.
Library
!=
"cpu"
{
case
opts
.
NumGPU
<
0
&&
layers
>
0
&&
gpus
[
0
]
.
Library
!=
"cpu"
:
opts
.
NumGPU
=
layers
}
}
// Loop through potential servers
finalErr
:=
fmt
.
Errorf
(
"no suitable llama servers found"
)
finalErr
:=
errors
.
New
(
"no suitable llama servers found"
)
if
len
(
adapters
)
>
1
{
return
nil
,
errors
.
New
(
"ollama supports only one lora adapter, but multiple were provided"
)
...
...
@@ -232,7 +232,7 @@ func NewLlamaServer(gpus gpu.GpuInfoList, model string, ggml *GGML, adapters, pr
params
=
append
(
params
,
"--parallel"
,
fmt
.
Sprintf
(
"%d"
,
numParallel
))
for
i
:=
0
;
i
<
len
(
servers
)
;
i
++
{
for
i
:=
range
len
(
servers
)
{
dir
:=
availableServers
[
servers
[
i
]]
if
dir
==
""
{
// Shouldn't happen
...
...
@@ -284,7 +284,7 @@ func NewLlamaServer(gpus gpu.GpuInfoList, model string, ggml *GGML, adapters, pr
server
:=
filepath
.
Join
(
dir
,
"ollama_llama_server"
)
if
runtime
.
GOOS
==
"windows"
{
server
=
server
+
".exe"
server
+
=
".exe"
}
// Detect tmp cleaners wiping out the file
...
...
@@ -315,7 +315,7 @@ func NewLlamaServer(gpus gpu.GpuInfoList, model string, ggml *GGML, adapters, pr
s
.
cmd
.
Stdout
=
os
.
Stdout
s
.
cmd
.
Stderr
=
s
.
status
visibleDevicesEnv
,
visibleDevicesEnvVal
:=
gpu
.
GpuInfoList
(
gpus
)
.
GetVisibleDevicesEnv
()
visibleDevicesEnv
,
visibleDevicesEnvVal
:=
gpu
s
.
GetVisibleDevicesEnv
()
pathEnvVal
:=
strings
.
Join
(
libraryPaths
,
string
(
filepath
.
ListSeparator
))
// Update or add the path and visible devices variable with our adjusted version
...
...
@@ -459,7 +459,7 @@ func (s *llmServer) getServerStatus(ctx context.Context) (ServerStatus, error) {
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
if
err
!=
nil
{
if
errors
.
Is
(
err
,
context
.
DeadlineExceeded
)
{
return
ServerStatusNotResponding
,
fmt
.
Errorf
(
"server not responding"
)
return
ServerStatusNotResponding
,
errors
.
New
(
"server not responding"
)
}
return
ServerStatusError
,
fmt
.
Errorf
(
"health resp: %w"
,
err
)
}
...
...
openai/openai.go
View file @
89d99001
...
...
@@ -245,7 +245,6 @@ func (w *writer) writeResponse(data []byte) (int, error) {
d
,
err
:=
json
.
Marshal
(
toChunk
(
w
.
id
,
chatResponse
))
if
err
!=
nil
{
return
0
,
err
}
w
.
ResponseWriter
.
Header
()
.
Set
(
"Content-Type"
,
"text/event-stream"
)
...
...
parser/parser_test.go
View file @
89d99001
...
...
@@ -10,6 +10,7 @@ import (
"unicode/utf16"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func
TestParseFileFile
(
t
*
testing
.
T
)
{
...
...
@@ -25,7 +26,7 @@ TEMPLATE template1
reader
:=
strings
.
NewReader
(
input
)
modelfile
,
err
:=
ParseFile
(
reader
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
expectedCommands
:=
[]
Command
{
{
Name
:
"model"
,
Args
:
"model1"
},
...
...
@@ -88,7 +89,7 @@ func TestParseFileFrom(t *testing.T) {
for
_
,
c
:=
range
cases
{
t
.
Run
(
""
,
func
(
t
*
testing
.
T
)
{
modelfile
,
err
:=
ParseFile
(
strings
.
NewReader
(
c
.
input
))
assert
.
ErrorIs
(
t
,
err
,
c
.
err
)
require
.
ErrorIs
(
t
,
err
,
c
.
err
)
if
modelfile
!=
nil
{
assert
.
Equal
(
t
,
c
.
expected
,
modelfile
.
Commands
)
}
...
...
@@ -105,7 +106,7 @@ PARAMETER param1
reader
:=
strings
.
NewReader
(
input
)
_
,
err
:=
ParseFile
(
reader
)
assert
.
ErrorIs
(
t
,
err
,
io
.
ErrUnexpectedEOF
)
require
.
ErrorIs
(
t
,
err
,
io
.
ErrUnexpectedEOF
)
}
func
TestParseFileBadCommand
(
t
*
testing
.
T
)
{
...
...
@@ -114,8 +115,7 @@ FROM foo
BADCOMMAND param1 value1
`
_
,
err
:=
ParseFile
(
strings
.
NewReader
(
input
))
assert
.
ErrorIs
(
t
,
err
,
errInvalidCommand
)
require
.
ErrorIs
(
t
,
err
,
errInvalidCommand
)
}
func
TestParseFileMessages
(
t
*
testing
.
T
)
{
...
...
@@ -201,7 +201,7 @@ MESSAGE system`,
for
_
,
c
:=
range
cases
{
t
.
Run
(
""
,
func
(
t
*
testing
.
T
)
{
modelfile
,
err
:=
ParseFile
(
strings
.
NewReader
(
c
.
input
))
assert
.
ErrorIs
(
t
,
err
,
c
.
err
)
require
.
ErrorIs
(
t
,
err
,
c
.
err
)
if
modelfile
!=
nil
{
assert
.
Equal
(
t
,
c
.
expected
,
modelfile
.
Commands
)
}
...
...
@@ -355,7 +355,7 @@ TEMPLATE """
for
_
,
c
:=
range
cases
{
t
.
Run
(
""
,
func
(
t
*
testing
.
T
)
{
modelfile
,
err
:=
ParseFile
(
strings
.
NewReader
(
c
.
multiline
))
assert
.
ErrorIs
(
t
,
err
,
c
.
err
)
require
.
ErrorIs
(
t
,
err
,
c
.
err
)
if
modelfile
!=
nil
{
assert
.
Equal
(
t
,
c
.
expected
,
modelfile
.
Commands
)
}
...
...
@@ -413,7 +413,7 @@ func TestParseFileParameters(t *testing.T) {
fmt
.
Fprintln
(
&
b
,
"FROM foo"
)
fmt
.
Fprintln
(
&
b
,
"PARAMETER"
,
k
)
modelfile
,
err
:=
ParseFile
(
&
b
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
[]
Command
{
{
Name
:
"model"
,
Args
:
"foo"
},
...
...
@@ -442,7 +442,7 @@ FROM foo
for
_
,
c
:=
range
cases
{
t
.
Run
(
""
,
func
(
t
*
testing
.
T
)
{
modelfile
,
err
:=
ParseFile
(
strings
.
NewReader
(
c
.
input
))
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
c
.
expected
,
modelfile
.
Commands
)
})
}
...
...
@@ -501,15 +501,14 @@ SYSTEM ""
for
_
,
c
:=
range
cases
{
t
.
Run
(
""
,
func
(
t
*
testing
.
T
)
{
modelfile
,
err
:=
ParseFile
(
strings
.
NewReader
(
c
))
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
modelfile2
,
err
:=
ParseFile
(
strings
.
NewReader
(
modelfile
.
String
()))
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
modelfile
,
modelfile2
)
})
}
}
func
TestParseFileUTF16ParseFile
(
t
*
testing
.
T
)
{
...
...
@@ -522,10 +521,10 @@ SYSTEM You are a utf16 file.
utf16File
:=
utf16
.
Encode
(
append
([]
rune
{
'\ufffe'
},
[]
rune
(
data
)
...
))
buf
:=
new
(
bytes
.
Buffer
)
err
:=
binary
.
Write
(
buf
,
binary
.
LittleEndian
,
utf16File
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
actual
,
err
:=
ParseFile
(
buf
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
expected
:=
[]
Command
{
{
Name
:
"model"
,
Args
:
"bob"
},
...
...
@@ -539,9 +538,9 @@ SYSTEM You are a utf16 file.
// simulate a utf16 be file
buf
=
new
(
bytes
.
Buffer
)
err
=
binary
.
Write
(
buf
,
binary
.
BigEndian
,
utf16File
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
actual
,
err
=
ParseFile
(
buf
)
assert
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
expected
,
actual
.
Commands
)
}
progress/progress.go
View file @
89d99001
...
...
@@ -59,7 +59,7 @@ func (p *Progress) StopAndClear() bool {
stopped
:=
p
.
stop
()
if
stopped
{
// clear all progress lines
for
i
:=
0
;
i
<
p
.
pos
;
i
++
{
for
i
:=
range
p
.
pos
{
if
i
>
0
{
fmt
.
Fprint
(
p
.
w
,
"
\0
33[A"
)
}
...
...
@@ -85,7 +85,7 @@ func (p *Progress) render() {
defer
fmt
.
Fprint
(
p
.
w
,
"
\0
33[?25h"
)
// clear already rendered progress lines
for
i
:=
0
;
i
<
p
.
pos
;
i
++
{
for
i
:=
range
p
.
pos
{
if
i
>
0
{
fmt
.
Fprint
(
p
.
w
,
"
\0
33[A"
)
}
...
...
readline/buffer.go
View file @
89d99001
...
...
@@ -52,7 +52,6 @@ func (b *Buffer) GetLineSpacing(line int) bool {
}
return
hasSpace
.
(
bool
)
}
func
(
b
*
Buffer
)
MoveLeft
()
{
...
...
@@ -117,15 +116,12 @@ func (b *Buffer) MoveRight() {
if
b
.
DisplayPos
%
b
.
LineWidth
==
0
{
fmt
.
Printf
(
CursorDown
+
CursorBOL
+
cursorRightN
(
len
(
b
.
Prompt
.
prompt
())))
}
else
if
(
b
.
DisplayPos
-
rLength
)
%
b
.
LineWidth
==
b
.
LineWidth
-
1
&&
hasSpace
{
fmt
.
Printf
(
CursorDown
+
CursorBOL
+
cursorRightN
(
len
(
b
.
Prompt
.
prompt
())
+
rLength
))
b
.
DisplayPos
+=
1
}
else
if
b
.
LineHasSpace
.
Size
()
>
0
&&
b
.
DisplayPos
%
b
.
LineWidth
==
b
.
LineWidth
-
1
&&
hasSpace
{
fmt
.
Printf
(
CursorDown
+
CursorBOL
+
cursorRightN
(
len
(
b
.
Prompt
.
prompt
())))
b
.
DisplayPos
+=
1
}
else
{
fmt
.
Print
(
cursorRightN
(
rLength
))
}
...
...
@@ -154,7 +150,7 @@ func (b *Buffer) MoveToStart() {
if
b
.
Pos
>
0
{
currLine
:=
b
.
DisplayPos
/
b
.
LineWidth
if
currLine
>
0
{
for
cnt
:=
0
;
cnt
<
currLine
;
cnt
++
{
for
range
currLine
{
fmt
.
Print
(
CursorUp
)
}
}
...
...
@@ -169,7 +165,7 @@ func (b *Buffer) MoveToEnd() {
currLine
:=
b
.
DisplayPos
/
b
.
LineWidth
totalLines
:=
b
.
DisplaySize
()
/
b
.
LineWidth
if
currLine
<
totalLines
{
for
cnt
:=
0
;
cnt
<
totalLines
-
currLine
;
cnt
++
{
for
range
totalLines
-
currLine
{
fmt
.
Print
(
CursorDown
)
}
remainder
:=
b
.
DisplaySize
()
%
b
.
LineWidth
...
...
@@ -185,7 +181,7 @@ func (b *Buffer) MoveToEnd() {
func
(
b
*
Buffer
)
DisplaySize
()
int
{
sum
:=
0
for
i
:=
0
;
i
<
b
.
Buf
.
Size
()
;
i
++
{
for
i
:=
range
b
.
Buf
.
Size
()
{
if
e
,
ok
:=
b
.
Buf
.
Get
(
i
);
ok
{
if
r
,
ok
:=
e
.
(
rune
);
ok
{
sum
+=
runewidth
.
RuneWidth
(
r
)
...
...
@@ -197,7 +193,6 @@ func (b *Buffer) DisplaySize() int {
}
func
(
b
*
Buffer
)
Add
(
r
rune
)
{
if
b
.
Pos
==
b
.
Buf
.
Size
()
{
b
.
AddChar
(
r
,
false
)
}
else
{
...
...
@@ -210,7 +205,6 @@ func (b *Buffer) AddChar(r rune, insert bool) {
b
.
DisplayPos
+=
rLength
if
b
.
Pos
>
0
{
if
b
.
DisplayPos
%
b
.
LineWidth
==
0
{
fmt
.
Printf
(
"%c"
,
r
)
fmt
.
Printf
(
"
\n
%s"
,
b
.
Prompt
.
AltPrompt
)
...
...
@@ -235,7 +229,6 @@ func (b *Buffer) AddChar(r rune, insert bool) {
}
else
{
b
.
LineHasSpace
.
Add
(
true
)
}
}
else
{
fmt
.
Printf
(
"%c"
,
r
)
}
...
...
@@ -356,7 +349,6 @@ func (b *Buffer) drawRemaining() {
func
(
b
*
Buffer
)
Remove
()
{
if
b
.
Buf
.
Size
()
>
0
&&
b
.
Pos
>
0
{
if
e
,
ok
:=
b
.
Buf
.
Get
(
b
.
Pos
-
1
);
ok
{
if
r
,
ok
:=
e
.
(
rune
);
ok
{
rLength
:=
runewidth
.
RuneWidth
(
r
)
...
...
@@ -382,7 +374,6 @@ func (b *Buffer) Remove() {
}
else
{
fmt
.
Print
(
" "
+
CursorLeft
)
}
}
else
if
(
b
.
DisplayPos
-
rLength
)
%
b
.
LineWidth
==
0
&&
hasSpace
{
fmt
.
Printf
(
CursorBOL
+
ClearToEOL
)
fmt
.
Printf
(
CursorUp
+
CursorBOL
+
cursorRightN
(
b
.
Width
))
...
...
@@ -391,10 +382,9 @@ func (b *Buffer) Remove() {
b
.
LineHasSpace
.
Remove
(
b
.
DisplayPos
/
b
.
LineWidth
-
1
)
}
b
.
DisplayPos
-=
1
}
else
{
fmt
.
Print
(
cursorLeftN
(
rLength
))
for
i
:=
0
;
i
<
rLength
;
i
++
{
for
range
rLength
{
fmt
.
Print
(
" "
)
}
fmt
.
Print
(
cursorLeftN
(
rLength
))
...
...
@@ -451,7 +441,7 @@ func (b *Buffer) DeleteBefore() {
func
(
b
*
Buffer
)
DeleteRemaining
()
{
if
b
.
DisplaySize
()
>
0
&&
b
.
Pos
<
b
.
DisplaySize
()
{
charsToDel
:=
b
.
Buf
.
Size
()
-
b
.
Pos
for
cnt
:=
0
;
cnt
<
charsToDel
;
cnt
++
{
for
range
charsToDel
{
b
.
Delete
()
}
}
...
...
@@ -495,7 +485,7 @@ func (b *Buffer) ClearScreen() {
if
currPos
>
0
{
targetLine
:=
currPos
/
b
.
LineWidth
if
targetLine
>
0
{
for
cnt
:=
0
;
cnt
<
targetLine
;
cnt
++
{
for
range
targetLine
{
fmt
.
Print
(
CursorDown
)
}
}
...
...
@@ -525,7 +515,7 @@ func (b *Buffer) Replace(r []rune) {
fmt
.
Printf
(
CursorBOL
+
ClearToEOL
)
for
i
:=
0
;
i
<
lineNums
;
i
++
{
for
range
lineNums
{
fmt
.
Print
(
CursorUp
+
CursorBOL
+
ClearToEOL
)
}
...
...
readline/history.go
View file @
89d99001
...
...
@@ -91,7 +91,7 @@ func (h *History) Add(l []rune) {
func
(
h
*
History
)
Compact
()
{
s
:=
h
.
Buf
.
Size
()
if
s
>
h
.
Limit
{
for
cnt
:=
0
;
cnt
<
s
-
h
.
Limit
;
cnt
++
{
for
range
s
-
h
.
Limit
{
h
.
Buf
.
Remove
(
0
)
}
}
...
...
@@ -139,7 +139,7 @@ func (h *History) Save() error {
defer
f
.
Close
()
buf
:=
bufio
.
NewWriter
(
f
)
for
cnt
:=
0
;
cnt
<
h
.
Size
()
;
cnt
++
{
for
cnt
:=
range
h
.
Size
()
{
v
,
_
:=
h
.
Buf
.
Get
(
cnt
)
line
,
_
:=
v
.
([]
rune
)
if
_
,
err
:=
buf
.
WriteString
(
string
(
line
)
+
"
\n
"
);
err
!=
nil
{
...
...
readline/readline.go
View file @
89d99001
...
...
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"os"
"syscall"
)
type
Prompt
struct
{
...
...
@@ -63,7 +62,7 @@ func New(prompt Prompt) (*Instance, error) {
func
(
i
*
Instance
)
Readline
()
(
string
,
error
)
{
if
!
i
.
Terminal
.
rawmode
{
fd
:=
int
(
syscall
.
Stdin
)
fd
:=
os
.
Stdin
.
Fd
(
)
termios
,
err
:=
SetRawMode
(
fd
)
if
err
!=
nil
{
return
""
,
err
...
...
@@ -80,8 +79,8 @@ func (i *Instance) Readline() (string, error) {
fmt
.
Print
(
prompt
)
defer
func
()
{
fd
:=
int
(
syscall
.
Stdin
)
//
nolint:
errcheck
fd
:=
os
.
Stdin
.
Fd
(
)
//nolint:errcheck
UnsetRawMode
(
fd
,
i
.
Terminal
.
termios
)
i
.
Terminal
.
rawmode
=
false
}()
...
...
@@ -136,7 +135,7 @@ func (i *Instance) Readline() (string, error) {
buf
.
MoveRight
()
case
CharBracketedPaste
:
var
code
string
for
cnt
:=
0
;
cnt
<
3
;
cnt
++
{
for
range
3
{
r
,
err
=
i
.
Terminal
.
Read
()
if
err
!=
nil
{
return
""
,
io
.
EOF
...
...
@@ -198,7 +197,7 @@ func (i *Instance) Readline() (string, error) {
buf
.
Remove
()
case
CharTab
:
// todo: convert back to real tabs
for
cnt
:=
0
;
cnt
<
8
;
cnt
++
{
for
range
8
{
buf
.
Add
(
' '
)
}
case
CharDelete
:
...
...
@@ -216,7 +215,7 @@ func (i *Instance) Readline() (string, error) {
case
CharCtrlW
:
buf
.
DeleteWord
()
case
CharCtrlZ
:
fd
:=
int
(
syscall
.
Stdin
)
fd
:=
os
.
Stdin
.
Fd
(
)
return
handleCharCtrlZ
(
fd
,
i
.
Terminal
.
termios
)
case
CharEnter
,
CharCtrlJ
:
output
:=
buf
.
String
()
...
...
@@ -248,7 +247,7 @@ func (i *Instance) HistoryDisable() {
}
func
NewTerminal
()
(
*
Terminal
,
error
)
{
fd
:=
int
(
syscall
.
Stdin
)
fd
:=
os
.
Stdin
.
Fd
(
)
termios
,
err
:=
SetRawMode
(
fd
)
if
err
!=
nil
{
return
nil
,
err
...
...
readline/readline_unix.go
View file @
89d99001
...
...
@@ -6,7 +6,7 @@ import (
"syscall"
)
func
handleCharCtrlZ
(
fd
int
,
termios
any
)
(
string
,
error
)
{
func
handleCharCtrlZ
(
fd
u
int
ptr
,
termios
any
)
(
string
,
error
)
{
t
:=
termios
.
(
*
Termios
)
if
err
:=
UnsetRawMode
(
fd
,
t
);
err
!=
nil
{
return
""
,
err
...
...
readline/readline_windows.go
View file @
89d99001
package
readline
func
handleCharCtrlZ
(
fd
int
,
state
any
)
(
string
,
error
)
{
func
handleCharCtrlZ
(
fd
u
int
ptr
,
state
any
)
(
string
,
error
)
{
// not supported
return
""
,
nil
}
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment