package ide import ( "os" "path/filepath" "strings" "github.com/host-uk/core/pkg/core" ) // Options holds configuration for the IDE service. type Options struct { // DefaultLanguage is the default language for new files. DefaultLanguage string } // Service provides IDE functionality for code editing, file management, and project operations. type Service struct { *core.ServiceRuntime[Options] config Options } // FileInfo represents information about a file for the editor. type FileInfo struct { Path string `json:"path"` Name string `json:"name"` Content string `json:"content"` Language string `json:"language"` IsNew bool `json:"isNew"` } // New creates a new IDE service instance. func New() (*Service, error) { return &Service{ config: Options{ DefaultLanguage: "typescript", }, }, nil } // Register creates and registers a new IDE service with the given Core instance. func Register(c *core.Core) (any, error) { s, err := New() if err != nil { return nil, err } s.ServiceRuntime = core.NewServiceRuntime[Options](c, Options{}) return s, nil } // ServiceName returns the canonical name for this service. func (s *Service) ServiceName() string { return "github.com/host-uk/core/ide" } // NewFile creates a new untitled file with the specified language. func (s *Service) NewFile(language string) FileInfo { if language == "" { language = s.config.DefaultLanguage } return FileInfo{ Path: "", Name: "Untitled", Content: "", Language: language, IsNew: true, } } // OpenFile reads a file from disk and returns its content with language detection. func (s *Service) OpenFile(path string) (FileInfo, error) { content, err := os.ReadFile(path) if err != nil { return FileInfo{}, err } return FileInfo{ Path: path, Name: filepath.Base(path), Content: string(content), Language: detectLanguage(path), IsNew: false, }, nil } // SaveFile saves content to the specified path. func (s *Service) SaveFile(path string, content string) error { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0755); err != nil { return err } return os.WriteFile(path, []byte(content), 0644) } // ReadFile reads content from a file without additional metadata. func (s *Service) ReadFile(path string) (string, error) { content, err := os.ReadFile(path) if err != nil { return "", err } return string(content), nil } // ListDirectory returns a list of files and directories in the given path. func (s *Service) ListDirectory(path string) ([]DirectoryEntry, error) { entries, err := os.ReadDir(path) if err != nil { return nil, err } result := make([]DirectoryEntry, 0, len(entries)) for _, entry := range entries { info, err := entry.Info() if err != nil { continue } result = append(result, DirectoryEntry{ Name: entry.Name(), Path: filepath.Join(path, entry.Name()), IsDir: entry.IsDir(), Size: info.Size(), }) } return result, nil } // DirectoryEntry represents a file or directory in a listing. type DirectoryEntry struct { Name string `json:"name"` Path string `json:"path"` IsDir bool `json:"isDir"` Size int64 `json:"size"` } // DetectLanguage returns the Monaco editor language for a given file path. func (s *Service) DetectLanguage(path string) string { return detectLanguage(path) } // detectLanguage maps file extensions to Monaco editor languages. func detectLanguage(path string) string { ext := strings.ToLower(filepath.Ext(path)) switch ext { case ".ts": return "typescript" case ".tsx": return "typescript" case ".js": return "javascript" case ".jsx": return "javascript" case ".go": return "go" case ".py": return "python" case ".rs": return "rust" case ".rb": return "ruby" case ".java": return "java" case ".c", ".h": return "c" case ".cpp", ".hpp", ".cc", ".cxx": return "cpp" case ".cs": return "csharp" case ".html", ".htm": return "html" case ".css": return "css" case ".scss": return "scss" case ".less": return "less" case ".json": return "json" case ".yaml", ".yml": return "yaml" case ".xml": return "xml" case ".md", ".markdown": return "markdown" case ".sql": return "sql" case ".sh", ".bash": return "shell" case ".ps1": return "powershell" case ".dockerfile": return "dockerfile" case ".toml": return "toml" case ".ini", ".cfg": return "ini" case ".swift": return "swift" case ".kt", ".kts": return "kotlin" case ".php": return "php" case ".r": return "r" case ".lua": return "lua" case ".pl", ".pm": return "perl" default: // Check for Dockerfile without extension if strings.ToLower(filepath.Base(path)) == "dockerfile" { return "dockerfile" } return "plaintext" } } // GetSupportedLanguages returns a list of languages supported by the editor. func (s *Service) GetSupportedLanguages() []LanguageInfo { return []LanguageInfo{ {ID: "typescript", Name: "TypeScript", Extensions: []string{".ts", ".tsx"}}, {ID: "javascript", Name: "JavaScript", Extensions: []string{".js", ".jsx"}}, {ID: "go", Name: "Go", Extensions: []string{".go"}}, {ID: "python", Name: "Python", Extensions: []string{".py"}}, {ID: "rust", Name: "Rust", Extensions: []string{".rs"}}, {ID: "java", Name: "Java", Extensions: []string{".java"}}, {ID: "csharp", Name: "C#", Extensions: []string{".cs"}}, {ID: "cpp", Name: "C++", Extensions: []string{".cpp", ".hpp", ".cc", ".cxx"}}, {ID: "c", Name: "C", Extensions: []string{".c", ".h"}}, {ID: "html", Name: "HTML", Extensions: []string{".html", ".htm"}}, {ID: "css", Name: "CSS", Extensions: []string{".css"}}, {ID: "scss", Name: "SCSS", Extensions: []string{".scss"}}, {ID: "json", Name: "JSON", Extensions: []string{".json"}}, {ID: "yaml", Name: "YAML", Extensions: []string{".yaml", ".yml"}}, {ID: "markdown", Name: "Markdown", Extensions: []string{".md", ".markdown"}}, {ID: "sql", Name: "SQL", Extensions: []string{".sql"}}, {ID: "shell", Name: "Shell", Extensions: []string{".sh", ".bash"}}, {ID: "xml", Name: "XML", Extensions: []string{".xml"}}, {ID: "swift", Name: "Swift", Extensions: []string{".swift"}}, {ID: "kotlin", Name: "Kotlin", Extensions: []string{".kt", ".kts"}}, {ID: "php", Name: "PHP", Extensions: []string{".php"}}, {ID: "ruby", Name: "Ruby", Extensions: []string{".rb"}}, } } // LanguageInfo describes a supported programming language. type LanguageInfo struct { ID string `json:"id"` Name string `json:"name"` Extensions []string `json:"extensions"` } // FileExists checks if a file exists at the given path. func (s *Service) FileExists(path string) bool { _, err := os.Stat(path) return err == nil } // CreateDirectory creates a new directory at the given path. func (s *Service) CreateDirectory(path string) error { return os.MkdirAll(path, 0755) } // DeleteFile removes a file at the given path. func (s *Service) DeleteFile(path string) error { return os.Remove(path) } // RenameFile renames/moves a file from oldPath to newPath. func (s *Service) RenameFile(oldPath, newPath string) error { return os.Rename(oldPath, newPath) }