| 170 | } |
| 171 | |
| 172 | func (api *API) readFileLines(_ context.Context, path string, offset, limit int64, limits workspacesdk.ReadFileLinesLimits) ReadFileLinesResponse { |
| 173 | errResp := func(msg string) ReadFileLinesResponse { |
| 174 | return ReadFileLinesResponse{Success: false, Error: msg} |
| 175 | } |
| 176 | |
| 177 | if !filepath.IsAbs(path) { |
| 178 | return errResp(fmt.Sprintf("file path must be absolute: %q", path)) |
| 179 | } |
| 180 | |
| 181 | f, err := api.filesystem.Open(path) |
| 182 | if err != nil { |
| 183 | if errors.Is(err, os.ErrNotExist) { |
| 184 | return errResp(fmt.Sprintf("file does not exist: %s", path)) |
| 185 | } |
| 186 | if errors.Is(err, os.ErrPermission) { |
| 187 | return errResp(fmt.Sprintf("permission denied: %s", path)) |
| 188 | } |
| 189 | return errResp(fmt.Sprintf("open file: %s", err)) |
| 190 | } |
| 191 | defer f.Close() |
| 192 | |
| 193 | stat, err := f.Stat() |
| 194 | if err != nil { |
| 195 | return errResp(fmt.Sprintf("stat file: %s", err)) |
| 196 | } |
| 197 | |
| 198 | if stat.IsDir() { |
| 199 | return errResp(fmt.Sprintf("not a file: %s", path)) |
| 200 | } |
| 201 | |
| 202 | fileSize := stat.Size() |
| 203 | if fileSize > limits.MaxFileSize { |
| 204 | return errResp(fmt.Sprintf( |
| 205 | "file is %d bytes which exceeds the maximum of %d bytes. Use grep, sed, or awk to extract the content you need, or use offset and limit to read a portion.", |
| 206 | fileSize, limits.MaxFileSize, |
| 207 | )) |
| 208 | } |
| 209 | |
| 210 | // Read the entire file (up to MaxFileSize). |
| 211 | data, err := io.ReadAll(f) |
| 212 | if err != nil { |
| 213 | return errResp(fmt.Sprintf("read file: %s", err)) |
| 214 | } |
| 215 | |
| 216 | // Split into lines. |
| 217 | content := string(data) |
| 218 | // Handle empty file. |
| 219 | if content == "" { |
| 220 | return ReadFileLinesResponse{ |
| 221 | Success: true, |
| 222 | FileSize: fileSize, |
| 223 | TotalLines: 0, |
| 224 | LinesRead: 0, |
| 225 | Content: "", |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | lines := strings.Split(content, "\n") |