{"id":19986087,"url":"https://github.com/cisstech/nge-ide","last_synced_at":"2025-05-04T07:31:05.403Z","repository":{"id":51274442,"uuid":"383157286","full_name":"cisstech/nge-ide","owner":"cisstech","description":"An extensible and flexible open source ide written in Angular.","archived":false,"fork":false,"pushed_at":"2024-11-01T19:59:31.000Z","size":17397,"stargazers_count":6,"open_issues_count":10,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-03T21:37:54.625Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cisstech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-05T13:51:08.000Z","updated_at":"2024-08-27T10:30:21.000Z","dependencies_parsed_at":"2023-09-29T19:17:31.168Z","dependency_job_id":"4dc1520f-f991-4f60-bcea-c64c4f1aac96","html_url":"https://github.com/cisstech/nge-ide","commit_stats":{"total_commits":167,"total_committers":5,"mean_commits":33.4,"dds":"0.23353293413173648","last_synced_commit":"bbe55385ca2f8d58740b10f0e50806a6a3b995bd"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cisstech%2Fnge-ide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cisstech%2Fnge-ide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cisstech%2Fnge-ide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cisstech%2Fnge-ide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cisstech","download_url":"https://codeload.github.com/cisstech/nge-ide/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224389260,"owners_count":17303237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T04:27:46.510Z","updated_at":"2025-05-04T07:31:05.396Z","avatar_url":"https://github.com/cisstech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD033 --\u003e\n\n\u003ch1 align=\"center\"\u003e NGE IDE\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./projects/demo/src/assets/images/nge.svg\" alt=\"Logo NGE\" width=\"120px\" /\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\nAn extensible and flexible open source ide written in Angular.\n\n[![Tests](https://github.com/cisstech/nge-ide/actions/workflows/ci.yml/badge.svg)](https://github.com/cisstech/nge-ide/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/cisstech/nge-ide/branch/main/graph/badge.svg)](https://codecov.io/gh/cisstech/nge-ide)\n[![codefactor](https://www.codefactor.io/repository/github/cisstech/nge-ide/badge/main)](https://www.codefactor.io/repository/github/cisstech/nge-ide/overview/main)\n[![GitHub Tag](https://img.shields.io/github/tag/cisstech/nge-ide.svg)](https://github.com/cisstech/nge-ide/tags)\n[![npm package](https://img.shields.io/npm/v/@cisstech/nge-ide.svg)](https://www.npmjs.org/package/@cisstech/nge-ide)\n[![NPM downloads](http://img.shields.io/npm/dm/@cisstech/nge-ide.svg)](https://npmjs.org/package/@cisstech/nge-ide)\n[![licence](https://img.shields.io/github/license/cisstech/nge-ide)](https://github.com/cisstech/nge-ide/blob/main/LICENSE)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\n\u003c/div\u003e\n\n## 📄 Docs\n\nDocumentation available at [https://cisstech.github.io/nge-ide/](https://cisstech.github.io/nge-ide/)\n\n## 📦 Installation\n\n```bash\nnpm install @cisstech/nge @cisstech/nge-ide monaco-editor marked\n```\n\n## 🚀 Quick Start\n\n### Basic Integration\n\nAdd the IDE to your Angular application by importing the `NgeIdeModule` in your app module:\n\n```typescript\nimport { NgModule } from '@angular/core'\nimport { BrowserModule } from '@angular/platform-browser'\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations'\n\nimport { NgeIdeModule } from '@cisstech/nge-ide'\nimport { NgeIdeExplorerModule } from '@cisstech/nge-ide/explorer'\nimport { NgeIdeSearchModule } from '@cisstech/nge-ide/search'\nimport { NgeIdeSettingsModule } from '@cisstech/nge-ide/settings'\n\nimport { NgeIdeProblemsModule } from '@cisstech/nge-ide/problems'\nimport { NgeIdeNotificationsModule } from '@cisstech/nge-ide/notifications'\n\n\n@NgModule({\n  imports: [\n    BrowserModule,\n    BrowserAnimationsModule,\n\n    NgeIdeModule,\n    NgeIdeExplorerModule,\n    NgeIdeSearchModule,\n    NgeIdeSettingsModule,\n\n    NgeIdeProblemsModule,\n    NgeIdeNotificationsModule,\n  ],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n```\n\n### Component Usage\n\nAdd the IDE root component to your template:\n\n```html\n\u003cide-root /\u003e\n```\n\n```ts\nimport { Component, OnDestroy, OnInit } from '@angular/core'\nimport { FileService, IdeService, MemFileProvider } from '@cisstech/nge-ide/core'\nimport { Subscription } from 'rxjs'\n\n@Component({\n  selector: 'app-component',\n  templateUrl: 'component.component.html',\n  styleUrls: ['component.component.scss'],\n})\nexport class AppComponent implements OnInit, OnDestroy {\n  private subscription?: Subscription\n\n  constructor(\n    private readonly ide: IdeService,\n    private readonly fileService: FileService\n  ) {}\n\n  ngOnInit() {\n    this.subscription = this.ide.onAfterStart(() =\u003e {\n      const provider = new MemFileProvider()\n      this.fileService.registerProvider(provider)\n      provider.roots.forEach((root) =\u003e {\n        this.fileService.registerFolders({\n          name: root.authority,\n          uri: root,\n        })\n      })\n    })\n  }\n\n  ngOnDestroy(): void {\n    this.subscription?.unsubscribe()\n  }\n}\n```\n\nThis basic setup will display the IDE with the default in memory file system and the optional contributions :\n\n- `NgeIdeExplorerModule` : Contribution to navigate the IDE files from the sidebar\n- `NgeIdeSearchModule` : Contribution to enable search view\n- `NgeIdeSettingsModule`: Contribution to enable settings view\n- `NgeIdeProblemsModule` : Contribution to enable problems view in the bottom area.\n- `NgeIdeNotificationsModule` : Contribution to enable notifications view in the bottom area.\n\n### Basic File System Setup\n\nIn this example configuration, the IDE use an in-memory file system, which is not what you want. You can add your own file system by implementing the `IFileSystemProvider` interface and registering it with the `FileService`.\n\n```typescript\nimport { Injectable } from '@angular/core'\nimport { HttpClient } from '@angular/common/http'\nimport { FileSystemProvider, FileSystemProviderCapabilities, IFile, FileSystemError } from '@cisstech/nge-ide/core'\nimport { firstValueFrom } from 'rxjs'\n\n@Injectable()\nexport class HttpFileSystemProvider extends FileSystemProvider {\n  readonly scheme = 'http' // URI scheme for this provider\n  readonly capabilities = FileSystemProviderCapabilities.FileRead // Read-only capabilities for this example\n\n  constructor(private readonly http: HttpClient) {\n    super()\n  }\n\n  // Check if provider has a specific capability\n  hasCapability(capability: FileSystemProviderCapabilities): boolean {\n    return (this.capabilities \u0026 capability) !== 0\n  }\n\n  // Implement read method to fetch file content via HTTP\n  async read(uri: monaco.Uri): Promise\u003cstring\u003e {\n    try {\n      // Convert IDE URI to actual HTTP URL\n      const url = `https://api.myservice.com/files${uri.path}`\n      const response = await firstValueFrom(this.http.get(url, { responseType: 'text' }))\n      return response\n    } catch (error) {\n      throw FileSystemError.FileNotFound(uri)\n    }\n  }\n\n  // Implement stat method to get file metadata\n  async stat(uri: monaco.Uri): Promise\u003cIFile\u003e {\n    try {\n      const url = `https://api.myservice.com/files/stat${uri.path}`\n      const response = await firstValueFrom(\n        this.http.get\u003c{\n          isDirectory: boolean\n          name: string\n          path: string\n        }\u003e(url)\n      )\n\n      return {\n        uri: uri,\n        isFolder: response.isDirectory,\n        readOnly: true, // Read-only in this example\n        name: response.name,\n      }\n    } catch (error) {\n      throw FileSystemError.FileNotFound(uri)\n    }\n  }\n\n  // Implement directory listing\n  async readDirectory(uri: monaco.Uri): Promise\u003cIFile[]\u003e {\n    try {\n      const url = `https://api.myservice.com/files/list${uri.path}`\n      const response = await firstValueFrom(\n        this.http.get\u003c\n          Array\u003c{\n            isDirectory: boolean\n            name: string\n            path: string\n          }\u003e\n        \u003e(url)\n      )\n\n      return response.map((item) =\u003e ({\n        uri: monaco.Uri.parse(`${this.scheme}://${uri.authority}${item.path}`),\n        isFolder: item.isDirectory,\n        readOnly: true,\n        name: item.name,\n      }))\n    } catch (error) {\n      throw FileSystemError.FileNotFound(uri)\n    }\n  }\n\n  // Implement other methods as needed based on your capabilities\n  // write, delete, rename, etc.\n}\n\n// Register the provider in a contribution\n@Injectable()\nexport class FileSystemContribution implements IContribution {\n  readonly id = 'app.filesystem-contribution'\n\n  constructor(\n    private readonly fileService: FileService,\n    private readonly httpFileSystemProvider: HttpFileSystemProvider\n  ) {}\n\n  activate() {\n    // Register the provider\n    this.fileService.registerProvider(this.httpFileSystemProvider)\n\n    // Register root folders\n    this.fileService.registerFolders([\n      {\n        name: 'My API Files',\n        uri: monaco.Uri.parse('http://api/'),\n      },\n      {\n        name: 'My Documentation',\n        uri: monaco.Uri.parse('http://docs/'),\n      },\n    ])\n  }\n}\n\n@NgModule({\n  providers: [HttpFileSystemProvider, { provide: CONTRIBUTION, multi: true, useClass: FileSystemContribution }],\n})\nexport class AppFileSystemModule {}\n```\n\nThe example above demonstrates how to implement a simple HTTP-based file system provider. When implementing your own provider, you should:\n\n1. Extend the `FileSystemProvider` class and specify a unique scheme\n2. Define which capabilities your provider supports (read, write, delete, etc.)\n3. Implement the required methods based on your provider's capabilities\n4. Register the provider with the `FileService` in a contribution\n5. Register root folders to make them visible in the file explorer\n\nFor a complete implementation, you may need to support additional capabilities like file searching, writing, deleting, etc., based on your application's requirements.\n\n## ⌨️ Development\n\n- Clone and install\n\n```bash\ngit clone https://github.com/cisstech/nge-ide\ncd nge-ide\nnpm install\n```\n\n- Serve demo\n\n```bash\nnpm run start\n```\n\nBrowser would open automatically at \u003chttp://localhost:4200/\u003e.\n\n## 💡 Contribution System Guide\n\nNGE IDE is built around a powerful contribution-based architecture that allows you to enhance and extend the IDE functionality. This guide walks you through understanding and building your own contributions.\n\n### Understanding Contributions\n\nIn NGE IDE, a \"contribution\" is any component, service, or feature that extends the IDE's functionality. Contributions follow a common interface:\n\n```typescript\nexport interface IContribution {\n  readonly id: string; // Unique identifier\n  activate?(injector: Injector): void or Promise\u003cvoid\u003e; // Setup code\n  deactivate?(): void or Promise\u003cvoid\u003e; // Cleanup code\n}\n```\n\nContributions are registered using Angular's dependency injection system:\n\n```typescript\n@NgModule({\n  providers: [{ provide: CONTRIBUTION, multi: true, useClass: MyContribution }],\n})\nexport class MyModule {}\n```\n\n### Step 1: Adding Core Contributions\n\nStart with the essential built-in contributions that provide basic IDE functionality:\n\n```typescript\nimport { NgModule } from '@angular/core'\nimport { BrowserModule } from '@angular/platform-browser'\n\nimport { NgeIdeModule } from '@cisstech/nge-ide'\nimport { NgeIdeExplorerModule } from '@cisstech/nge-ide/explorer' // File explorer\nimport { NgeIdeSearchModule } from '@cisstech/nge-ide/search' // Search functionality\nimport { NgeIdeSettingsModule } from '@cisstech/nge-ide/settings' // Settings UI\n\n@NgModule({\n  imports: [BrowserModule, NgeIdeModule, NgeIdeExplorerModule, NgeIdeSearchModule, NgeIdeSettingsModule],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n```\n\nThis basic setup gives you:\n\n- A fully functional IDE layout with sidebars and panels\n- File explorer for navigating your files\n- Search capabilities across your codebase\n- Settings management interface\n\n### Step 2: Adding File System Support\n\nNext, create a custom file system provider to access your application's files:\n\n```typescript\n@Injectable()\nexport class MyFileSystemContribution implements IContribution {\n  readonly id = 'app.file-system'\n\n  constructor(\n    private readonly fileService: FileService,\n    private readonly httpFs: HttpFileSystemProvider\n  ) {}\n\n  activate() {\n    // Register the file provider\n    this.fileService.registerProvider(this.httpFs)\n\n    // Register root folders to appear in the explorer\n    this.fileService.registerFolders({\n      name: 'Project Files',\n      uri: monaco.Uri.parse('http://my-project/'),\n    })\n  }\n}\n```\n\nThe `FileService` exposes these key APIs:\n\n- `registerProvider(provider)`: Register a file system provider\n- `registerFolders(folders)`: Register root folders to show in explorer\n- `open(uri)`, `save(uri)`, `close(uri)`: File operations\n- `find(uri)`, `findChildren(file)`: Navigation methods\n- `isDirty(uri)`: Check if file has unsaved changes\n\n### Step 3: Adding View Containers and Views\n\nView containers group related views in the IDE sidebars:\n\n```typescript\n@Injectable()\nexport class MyViewContribution implements IContribution {\n  readonly id = 'app.my-views'\n\n  activate(injector: Injector) {\n    const viewContainerService = injector.get(ViewContainerService)\n    const viewService = injector.get(ViewService)\n\n    // 1. Register a container in the sidebar\n    viewContainerService.register(\n      new (class extends SidebarContainer {\n        readonly id = 'app.my-container'\n        readonly title = 'My Tools'\n        readonly icon = new CodIcon('tools')\n        readonly side = 'left' // 'left' or 'right'\n        readonly align = 'top' // 'top' or 'bottom'\n      })()\n    )\n\n    // 2. Register views inside the container\n    viewService.register({\n      id: 'app.my-view',\n      title: 'My View',\n      viewContainerId: 'app.my-container',\n      component: () =\u003e MyViewComponent,\n    })\n  }\n}\n```\n\nKey view APIs:\n\n- `ViewContainerService`: Manages containers (sidebars, panels)\n- `ViewService`: Manages individual views within containers\n- Built-in containers: `leftSideBar`, `rightSideBar`, `bottomPanel`\n\n### Step 4: Adding Commands\n\nCommands are actions that can be triggered by users through menus, buttons, keyboard shortcuts or api calls to command service:\n\n```typescript\n@Injectable()\nexport class MyCommandContribution implements IContribution {\n  readonly id = 'app.my-commands'\n\n  constructor(\n    private readonly commandService: CommandService,\n    private readonly toolbarService: ToolbarService\n  ) {}\n\n  activate() {\n    // 1. Create and register a command\n    const myCommand: ICommand = {\n      id: 'app.myCommand',\n      label: 'Do Something',\n      icon: new CodIcon('zap'),\n      get enabled() {\n        return true\n      },\n      execute: () =\u003e {\n        console.log('Command executed!')\n      },\n    }\n\n    this.commandService.register(myCommand)\n\n    // 2. Add the command to the editor toolbar\n    this.toolbarService.register(\n      new ToolbarButton({\n        group: ToolbarGroups.EDIT, // Predefined toolbar groups\n        command: myCommand,\n        priority: 10,\n      })\n    )\n  }\n}\n```\n\nCommand system APIs:\n\n- `CommandService`: Register and execute commands\n- `ToolbarService`: Add buttons to editor toolbars\n- `KeyBindService`: Register keyboard shortcuts\n- Predefined toolbar groups: `FILE`, `EDIT`, `SELECTION`, `VIEW`, `GO`\n- Use command as angular service to access to dependency injection in the constructor.\n\n### Step 5: Editor Enhancements\n\nEnhance the editor with custom functionality:\n\n```typescript\n@Injectable()\nexport class MyEditorContribution implements IContribution {\n  readonly id = 'app.editor-contrib'\n\n  constructor(\n    private readonly editorService: EditorService,\n    private readonly monacoService: MonacoService,\n    private readonly previewService: PreviewService\n  ) {}\n\n  activate() {\n    // 1. Register custom file editors\n    this.editorService.registerEditors(new MyCustomEditor())\n\n    // 2. Register custom preview handlers for files\n    this.previewService.register(new ImagePreviewHandler())\n\n    // 3. Listen for editor events\n    this.monacoService.onDidCreateEditor.subscribe((editor) =\u003e {\n      // Configure the Monaco editor instance\n      editor.updateOptions({ lineNumbers: 'on' })\n    })\n\n    // 4. Register editor commands\n    this.editorService.registerCommands(MyEditorCommandClass)\n  }\n}\n```\n\nEditor APIs:\n\n- `EditorService`: Manage editors and editor groups\n- `MonacoService`: Direct access to Monaco editor instances\n- `PreviewService`: Register preview handlers for files\n\n### Step 6: Other API Services\n\nNGE IDE provides several other services for building rich IDE features:\n\n```typescript\n@Injectable()\nexport class MyAdvancedContribution implements IContribution {\n  readonly id = 'app.advanced'\n\n  constructor(\n    private readonly notificationService: NotificationService,\n    private readonly dialogService: DialogService,\n    private readonly statusBarService: StatusBarService,\n    private readonly taskService: TaskService,\n    private readonly diagnosticService: DiagnosticService,\n    private readonly settingsService: SettingsService\n  ) {}\n\n  activate() {\n    // Show notifications\n    this.notificationService.publish(new InfoNotification('IDE initialized'))\n\n    // Add item to status bar\n    this.statusBarService.register({\n      id: 'app.status.item',\n      side: 'right',\n      priority: 10,\n      content: 'Ready',\n      tooltip: 'System status',\n    })\n\n    // Report diagnostics for a file\n    const uri = monaco.Uri.parse('file:///myfile.ts')\n    this.diagnosticService.setDiagnostics(uri, [\n      {\n        message: 'Variable not used',\n        severity: DiagnosticSeverity.Warning,\n        range: {\n          start: { lineNumber: 5, column: 10 },\n          end: { lineNumber: 5, column: 15 },\n        },\n      },\n    ])\n\n    // Run background task with progress\n    const task = this.taskService.run('Processing files')\n    setTimeout(() =\u003e task.end(), 3000)\n\n    // Access or modify settings\n    this.settingsService.set('editor', 'fontSize', 14)\n  }\n}\n```\n\nAdditional available services:\n\n- `NotificationService`: Show notifications to users\n- `DialogService`: Display modal dialogs\n- `StatusBarService`: Add items to the status bar\n- `TaskService`: Run and track background tasks\n- `DiagnosticService`: Report problems in files\n- `SettingsService`: Manage user/workspace settings\n\n### Putting It All Together\n\nA complete module that contributes a file system, views, and commands:\n\n```typescript\n@NgModule({\n  imports: [NgeIdeModule, NgeIdeExplorerModule, NgeIdeSearchModule],\n  declarations: [MyViewComponent],\n  providers: [\n    MyFileSystemProvider,\n    { provide: CONTRIBUTION, multi: true, useClass: MyFileSystemContribution },\n    { provide: CONTRIBUTION, multi: true, useClass: MyViewContribution },\n    { provide: CONTRIBUTION, multi: true, useClass: MyCommandContribution },\n    { provide: CONTRIBUTION, multi: true, useClass: MyEditorContribution },\n  ],\n})\nexport class MyIDEFeatureModule {}\n```\n\nThis progressive approach allows you to build up your IDE's functionality layer by layer, from basic file system access to rich editor features, all through the unified contribution system.\n\n## 🤝 Contribution\n\nContributions are always welcome. \u003cbr/\u003e\n\nPlease read our [CONTRIBUTING.md](https://github.com/cisstech/nge-ide/blob/main/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/cisstech/nge-ide/pulls) or as [GitHub issues](https://github.com/cisstech/nge-ide/issues).\n\nPlease just make sure that ...\n\nYour code style matches with the rest of the project\n\nUnit tests pass\n\nLinter passes\n\n## ❓ Support Development\n\nThe use of this library is totally free.\n\nAs the owner and primary maintainer of this project, I am putting a lot of time and effort beside my job, my family and my private time to bring the best support I can by answering questions, addressing issues and improving the library to provide more and more features over time.\n\nIf this project has been useful, that it helped you or your business to save precious time, don't hesitate to give it a star to support its maintenance and future development.\n\n## ✨ License\n\nMIT © [Mamadou Cisse](https://github.com/cisstech)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcisstech%2Fnge-ide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcisstech%2Fnge-ide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcisstech%2Fnge-ide/lists"}