syntax = "proto3";
package zed.messages;

message Envelope {
    uint32 id = 1;
    optional uint32 responding_to = 2;
    optional uint32 original_sender_id = 3;
    oneof payload {
        Ack ack = 4;
        Error error = 5;
        Ping ping = 6;
        Test test = 7;

        RegisterProject register_project = 8;
        RegisterProjectResponse register_project_response = 9;
        UnregisterProject unregister_project = 10;
        RequestJoinProject request_join_project = 11;
        RespondToJoinProjectRequest respond_to_join_project_request = 12;
        JoinProjectRequestCancelled join_project_request_cancelled = 13;
        JoinProject join_project = 14;
        JoinProjectResponse join_project_response = 15;
        LeaveProject leave_project = 16;
        AddProjectCollaborator add_project_collaborator = 17;
        RemoveProjectCollaborator remove_project_collaborator = 18;
        ProjectUnshared project_unshared = 19;

        GetDefinition get_definition = 20;
        GetDefinitionResponse get_definition_response = 21;
        GetReferences get_references = 22;
        GetReferencesResponse get_references_response = 23;
        GetDocumentHighlights get_document_highlights = 24;
        GetDocumentHighlightsResponse get_document_highlights_response = 25;
        GetProjectSymbols get_project_symbols = 26;
        GetProjectSymbolsResponse get_project_symbols_response = 27;
        OpenBufferForSymbol open_buffer_for_symbol = 28;
        OpenBufferForSymbolResponse open_buffer_for_symbol_response = 29;

        RegisterWorktree register_worktree = 30;
        UnregisterWorktree unregister_worktree = 31;
        UpdateWorktree update_worktree = 32;

        CreateProjectEntry create_project_entry = 33;
        RenameProjectEntry rename_project_entry = 34;
        CopyProjectEntry copy_project_entry = 35;
        DeleteProjectEntry delete_project_entry = 36;
        ProjectEntryResponse project_entry_response = 37;

        UpdateDiagnosticSummary update_diagnostic_summary = 38;
        StartLanguageServer start_language_server = 39;
        UpdateLanguageServer update_language_server = 40;

        OpenBufferById open_buffer_by_id = 41;
        OpenBufferByPath open_buffer_by_path = 42;
        OpenBufferResponse open_buffer_response = 43;
        UpdateBuffer update_buffer = 44;
        UpdateBufferFile update_buffer_file = 45;
        SaveBuffer save_buffer = 46;
        BufferSaved buffer_saved = 47;
        BufferReloaded buffer_reloaded = 48;
        ReloadBuffers reload_buffers = 49;
        ReloadBuffersResponse reload_buffers_response = 50;
        FormatBuffers format_buffers = 51;
        FormatBuffersResponse format_buffers_response = 52;
        GetCompletions get_completions = 53;
        GetCompletionsResponse get_completions_response = 54;
        ApplyCompletionAdditionalEdits apply_completion_additional_edits = 55;
        ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 56;
        GetCodeActions get_code_actions = 57;
        GetCodeActionsResponse get_code_actions_response = 58;
        ApplyCodeAction apply_code_action = 59;
        ApplyCodeActionResponse apply_code_action_response = 60;
        PrepareRename prepare_rename = 61;
        PrepareRenameResponse prepare_rename_response = 62;
        PerformRename perform_rename = 63;
        PerformRenameResponse perform_rename_response = 64;
        SearchProject search_project = 65;
        SearchProjectResponse search_project_response = 66;

        GetChannels get_channels = 67;
        GetChannelsResponse get_channels_response = 68;
        JoinChannel join_channel = 69;
        JoinChannelResponse join_channel_response = 70;
        LeaveChannel leave_channel = 71;
        SendChannelMessage send_channel_message = 72;
        SendChannelMessageResponse send_channel_message_response = 73;
        ChannelMessageSent channel_message_sent = 74;
        GetChannelMessages get_channel_messages = 75;
        GetChannelMessagesResponse get_channel_messages_response = 76;

        UpdateContacts update_contacts = 77;
        UpdateInviteInfo update_invite_info = 78;
        ShowContacts show_contacts = 79;

        GetUsers get_users = 80;
        FuzzySearchUsers fuzzy_search_users = 81;
        UsersResponse users_response = 82;
        RequestContact request_contact = 83;
        RespondToContactRequest respond_to_contact_request = 84;
        RemoveContact remove_contact = 85;

        Follow follow = 86;
        FollowResponse follow_response = 87;
        UpdateFollowers update_followers = 88;
        Unfollow unfollow = 89;
    }
}

// Messages

message Ping {}

message Ack {}

message Error {
    string message = 1;
}

message Test {
    uint64 id = 1;
}

message RegisterProject {}

message RegisterProjectResponse {
    uint64 project_id = 1;
}

message UnregisterProject {
    uint64 project_id = 1;
}

message RequestJoinProject {
    uint64 requester_id = 1;
    uint64 project_id = 2;
}

message RespondToJoinProjectRequest {
    uint64 requester_id = 1;
    uint64 project_id = 2;
    bool allow = 3;
}

message JoinProjectRequestCancelled {
    uint64 requester_id = 1;
    uint64 project_id = 2;
}

message JoinProject {
    uint64 project_id = 1;
}

message JoinProjectResponse {
    oneof variant {
        Accept accept = 1;
        Decline decline = 2;
    }

    message Accept {
        uint32 replica_id = 1;
        repeated Worktree worktrees = 2;
        repeated Collaborator collaborators = 3;
        repeated LanguageServer language_servers = 4;        
    }
    
    message Decline {
        Reason reason = 1;

        enum Reason {
            Declined = 0;
            Closed = 1;
            WentOffline = 2;
        }
    }
}

message LeaveProject {
    uint64 project_id = 1;
}

message RegisterWorktree {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
    string root_name = 3;
    bool visible = 4;
}

message UnregisterWorktree {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
}

message UpdateWorktree {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
    string root_name = 3;
    repeated Entry updated_entries = 4;
    repeated uint64 removed_entries = 5;
    uint64 scan_id = 6;
}

message CreateProjectEntry {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
    bytes path = 3;
    bool is_directory = 4;
}

message RenameProjectEntry {
    uint64 project_id = 1;
    uint64 entry_id = 2;
    bytes new_path = 3;
}

message CopyProjectEntry {
    uint64 project_id = 1;
    uint64 entry_id = 2;
    bytes new_path = 3;
}

message DeleteProjectEntry {
    uint64 project_id = 1;
    uint64 entry_id = 2;
}

message ProjectEntryResponse {
    Entry entry = 1;
    uint64 worktree_scan_id = 2;
}

message AddProjectCollaborator {
    uint64 project_id = 1;
    Collaborator collaborator = 2;
}

message RemoveProjectCollaborator {
    uint64 project_id = 1;
    uint32 peer_id = 2;
}

message ProjectUnshared {
    uint64 project_id = 1;
}

message GetDefinition {
     uint64 project_id = 1;
     uint64 buffer_id = 2;
     Anchor position = 3;
     repeated VectorClockEntry version = 4;
 }

message GetDefinitionResponse {
    repeated Location locations = 1;
}

message GetReferences {
     uint64 project_id = 1;
     uint64 buffer_id = 2;
     Anchor position = 3;
     repeated VectorClockEntry version = 4;
 }

message GetReferencesResponse {
    repeated Location locations = 1;
}

message GetDocumentHighlights {
     uint64 project_id = 1;
     uint64 buffer_id = 2;
     Anchor position = 3;
     repeated VectorClockEntry version = 4;
 }

message GetDocumentHighlightsResponse {
    repeated DocumentHighlight highlights = 1;
}

message Location {
    Buffer buffer = 1;
    Anchor start = 2;
    Anchor end = 3;
}

message DocumentHighlight {
    Kind kind = 1;
    Anchor start = 2;
    Anchor end = 3;

    enum Kind {
        Text = 0;
        Read = 1;
        Write = 2;
    }
}

message GetProjectSymbols {
    uint64 project_id = 1;
    string query = 2;
}

message GetProjectSymbolsResponse {
    repeated Symbol symbols = 4;
}

message Symbol {
    uint64 source_worktree_id = 1;
    uint64 worktree_id = 2;
    string language_server_name = 3;
    string name = 4;
    int32 kind = 5;
    string path = 6;
    Point start = 7;
    Point end = 8;
    bytes signature = 9;
}

message OpenBufferForSymbol {
    uint64 project_id = 1;
    Symbol symbol = 2;
}

message OpenBufferForSymbolResponse {
    Buffer buffer = 1;
}

message OpenBufferByPath {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
    string path = 3;
}

message OpenBufferById {
    uint64 project_id = 1;
    uint64 id = 2;
}

message OpenBufferResponse {
    Buffer buffer = 1;
}

message CloseBuffer {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
}

message UpdateBuffer {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    repeated Operation operations = 3;
}

message UpdateBufferFile {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    File file = 3;
}

message SaveBuffer {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    repeated VectorClockEntry version = 3;
}

message BufferSaved {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    repeated VectorClockEntry version = 3;
    Timestamp mtime = 4;
}

message BufferReloaded {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    repeated VectorClockEntry version = 3;
    Timestamp mtime = 4;
}

message ReloadBuffers {
    uint64 project_id = 1;
    repeated uint64 buffer_ids = 2;
}

message ReloadBuffersResponse {
    ProjectTransaction transaction = 1;
}

message FormatBuffers {
    uint64 project_id = 1;
    repeated uint64 buffer_ids = 2;
}

message FormatBuffersResponse {
    ProjectTransaction transaction = 1;
}

message GetCompletions {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    Anchor position = 3;
    repeated VectorClockEntry version = 4;
}

message GetCompletionsResponse {
    repeated Completion completions = 1;
    repeated VectorClockEntry version = 2;
}

message ApplyCompletionAdditionalEdits {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    Completion completion = 3;
}

message ApplyCompletionAdditionalEditsResponse {
    Transaction transaction = 1;
}

message Completion {
    Anchor old_start = 1;
    Anchor old_end = 2;
    string new_text = 3;
    bytes lsp_completion = 4;
}

message GetCodeActions {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    Anchor start = 3;
    Anchor end = 4;
    repeated VectorClockEntry version = 5;
}

message GetCodeActionsResponse {
    repeated CodeAction actions = 1;
    repeated VectorClockEntry version = 2;
}

message ApplyCodeAction {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    CodeAction action = 3;
}

message ApplyCodeActionResponse {
    ProjectTransaction transaction = 1;
}

message PrepareRename {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    Anchor position = 3;
    repeated VectorClockEntry version = 4;
}

message PrepareRenameResponse {
    bool can_rename = 1;
    Anchor start = 2;
    Anchor end = 3;
    repeated VectorClockEntry version = 4;
}

message PerformRename {
    uint64 project_id = 1;
    uint64 buffer_id = 2;
    Anchor position = 3;
    string new_name = 4;
    repeated VectorClockEntry version = 5;
}

message PerformRenameResponse {
    ProjectTransaction transaction = 2;
}

message SearchProject {
    uint64 project_id = 1;
    string query = 2;
    bool regex = 3;
    bool whole_word = 4;
    bool case_sensitive = 5;
}

message SearchProjectResponse {
    repeated Location locations = 1;
}

message CodeAction {
    Anchor start = 1;
    Anchor end = 2;
    bytes lsp_action = 3;
}

message ProjectTransaction {
    repeated Buffer buffers = 1;
    repeated Transaction transactions = 2;
}

message Transaction {
    LocalTimestamp id = 1;
    repeated LocalTimestamp edit_ids = 2;
    repeated VectorClockEntry start = 3;
    repeated VectorClockEntry end = 4;
    repeated Range ranges = 5;
}

message LocalTimestamp {
    uint32 replica_id = 1;
    uint32 value = 2;
}

message LanguageServer {
    uint64 id = 1;
    string name = 2;
}

message StartLanguageServer {
    uint64 project_id = 1;
    LanguageServer server = 2;
}

message UpdateDiagnosticSummary {
    uint64 project_id = 1;
    uint64 worktree_id = 2;
    DiagnosticSummary summary = 3;
}

message DiagnosticSummary {
    string path = 1;
    uint32 error_count = 2;
    uint32 warning_count = 3;
}

message UpdateLanguageServer {
    uint64 project_id = 1;
    uint64 language_server_id = 2;
    oneof variant {
        LspWorkStart work_start = 3;
        LspWorkProgress work_progress = 4;
        LspWorkEnd work_end = 5;
        LspDiskBasedDiagnosticsUpdating disk_based_diagnostics_updating = 6;
        LspDiskBasedDiagnosticsUpdated disk_based_diagnostics_updated = 7;
    }
}

message LspWorkStart {
    string token = 1;
}

message LspWorkProgress {
    string token = 1;
    optional string message = 2;
    optional uint32 percentage = 3;
}

message LspWorkEnd {
    string token = 1;
}

message LspDiskBasedDiagnosticsUpdating {}

message LspDiskBasedDiagnosticsUpdated {}

message GetChannels {}

message GetChannelsResponse {
    repeated Channel channels = 1;
}

message JoinChannel {
    uint64 channel_id = 1;
}

message JoinChannelResponse {
    repeated ChannelMessage messages = 1;
    bool done = 2;
}

message LeaveChannel {
    uint64 channel_id = 1;
}

message GetUsers {
    repeated uint64 user_ids = 1;
}

message FuzzySearchUsers {
    string query = 1;
}

message UsersResponse {
    repeated User users = 1;
}

message RequestContact {
    uint64 responder_id = 1;
}

message RemoveContact {
    uint64 user_id = 1;
}

message RespondToContactRequest {
    uint64 requester_id = 1;
    ContactRequestResponse response = 2;
}

enum ContactRequestResponse {
    Accept = 0;
    Decline = 1;
    Block = 2;
    Dismiss = 3;
}

message SendChannelMessage {
    uint64 channel_id = 1;
    string body = 2;
    Nonce nonce = 3;
}

message SendChannelMessageResponse {
    ChannelMessage message = 1;
}

message ChannelMessageSent {
    uint64 channel_id = 1;
    ChannelMessage message = 2;
}

message GetChannelMessages {
    uint64 channel_id = 1;
    uint64 before_message_id = 2;
}

message GetChannelMessagesResponse {
    repeated ChannelMessage messages = 1;
    bool done = 2;
}

message UpdateContacts {
    repeated Contact contacts = 1;
    repeated uint64 remove_contacts = 2;
    repeated IncomingContactRequest incoming_requests = 3;
    repeated uint64 remove_incoming_requests = 4;
    repeated uint64 outgoing_requests = 5;
    repeated uint64 remove_outgoing_requests = 6;
}

message UpdateInviteInfo {
    string url = 1;
    uint32 count = 2;
}

message ShowContacts {}

message IncomingContactRequest {
    uint64 requester_id = 1;
    bool should_notify = 2;
}

message UpdateDiagnostics {
    uint32 replica_id = 1;
    uint32 lamport_timestamp = 2;
    repeated Diagnostic diagnostics = 3;
}

message Follow {
    uint64 project_id = 1;
    uint32 leader_id = 2;
}

message FollowResponse {
    optional uint64 active_view_id = 1;
    repeated View views = 2;
}

message UpdateFollowers {
    uint64 project_id = 1;
    repeated uint32 follower_ids = 2;
    oneof variant {
        UpdateActiveView update_active_view = 3;
        View create_view = 4;
        UpdateView update_view = 5;
    }
}

message Unfollow {
    uint64 project_id = 1;
    uint32 leader_id = 2;
}

// Entities

message UpdateActiveView {
    optional uint64 id = 1;
    optional uint32 leader_id = 2;
}

message UpdateView {
    uint64 id = 1;
    optional uint32 leader_id = 2;

    oneof variant {
        Editor editor = 3;
    }

    message Editor {
        repeated Selection selections = 1;
        Anchor scroll_top_anchor = 2;
        float scroll_x = 3;
        float scroll_y = 4;
    }
}

message View {
    uint64 id = 1;
    optional uint32 leader_id = 2;

    oneof variant {
        Editor editor = 3;
    }

    message Editor {
        uint64 buffer_id = 1;
        repeated Selection selections = 2;
        Anchor scroll_top_anchor = 3;
        float scroll_x = 4;
        float scroll_y = 5;
    }
}

message Collaborator {
    uint32 peer_id = 1;
    uint32 replica_id = 2;
    uint64 user_id = 3;
}

message User {
    uint64 id = 1;
    string github_login = 2;
    string avatar_url = 3;
}

message Worktree {
    uint64 id = 1;
    string root_name = 2;
    repeated Entry entries = 3;
    repeated DiagnosticSummary diagnostic_summaries = 4;
    bool visible = 5;
    uint64 scan_id = 6;
}

message File {
    uint64 worktree_id = 1;
    optional uint64 entry_id = 2;
    string path = 3;
    Timestamp mtime = 4;
}

message Entry {
    uint64 id = 1;
    bool is_dir = 2;
    bytes path = 3;
    uint64 inode = 4;
    Timestamp mtime = 5;
    bool is_symlink = 6;
    bool is_ignored = 7;
}

message Buffer {
    oneof variant {
        uint64 id = 1;
        BufferState state = 2;
    }
}

message BufferState {
    uint64 id = 1;
    optional File file = 2;
    string base_text = 3;
    repeated Operation operations = 4;
    repeated SelectionSet selections = 5;
    repeated Diagnostic diagnostics = 6;
    uint32 diagnostics_timestamp = 7;
    repeated string completion_triggers = 8;
}

message SelectionSet {
    uint32 replica_id = 1;
    repeated Selection selections = 2;
    uint32 lamport_timestamp = 3;
    bool line_mode = 4;
}

message Selection {
    uint64 id = 1;
    Anchor start = 2;
    Anchor end = 3;
    bool reversed = 4;
}

message Anchor {
    uint32 replica_id = 1;
    uint32 local_timestamp = 2;
    uint64 offset = 3;
    Bias bias = 4;
    optional uint64 buffer_id = 5;
}

enum Bias {
    Left = 0;
    Right = 1;
}

message Diagnostic {
    Anchor start = 1;
    Anchor end = 2;
    Severity severity = 3;
    string message = 4;
    optional string code = 5;
    uint64 group_id = 6;
    bool is_primary = 7;
    bool is_valid = 8;
    bool is_disk_based = 9;
    bool is_unnecessary = 10;

    enum Severity {
        None = 0;
        Error = 1;
        Warning = 2;
        Information = 3;
        Hint = 4;
    }
}

message Operation {
    oneof variant {
        Edit edit = 1;
        Undo undo = 2;
        UpdateSelections update_selections = 3;
        UpdateDiagnostics update_diagnostics = 4;
        UpdateCompletionTriggers update_completion_triggers = 5;
    }

    message Edit {
        uint32 replica_id = 1;
        uint32 local_timestamp = 2;
        uint32 lamport_timestamp = 3;
        repeated VectorClockEntry version = 4;
        repeated Range ranges = 5;
        repeated string new_text = 6;
    }

    message Undo {
        uint32 replica_id = 1;
        uint32 local_timestamp = 2;
        uint32 lamport_timestamp = 3;
        repeated VectorClockEntry version = 4;
        repeated Range transaction_ranges = 5;
        repeated VectorClockEntry transaction_version = 6;
        repeated UndoCount counts = 7;
    }

    message UpdateSelections {
        uint32 replica_id = 1;
        uint32 lamport_timestamp = 2;
        repeated Selection selections = 3;
        bool line_mode = 4;
    }

    message UpdateCompletionTriggers {
        uint32 replica_id = 1;
        uint32 lamport_timestamp = 2;
        repeated string triggers = 3;
    }
}

message UndoMapEntry {
    uint32 replica_id = 1;
    uint32 local_timestamp = 2;
    repeated UndoCount counts = 3;
}

message UndoCount {
    uint32 replica_id = 1;
    uint32 local_timestamp = 2;
    uint32 count = 3;
}

message VectorClockEntry {
    uint32 replica_id = 1;
    uint32 timestamp = 2;
}

message Timestamp {
    uint64 seconds = 1;
    uint32 nanos = 2;
}

message Range {
    uint64 start = 1;
    uint64 end = 2;
}

message Point {
    uint32 row = 1;
    uint32 column = 2;
}

message Nonce {
    uint64 upper_half = 1;
    uint64 lower_half = 2;
}

message Channel {
    uint64 id = 1;
    string name = 2;
}

message ChannelMessage {
    uint64 id = 1;
    string body = 2;
    uint64 timestamp = 3;
    uint64 sender_id = 4;
    Nonce nonce = 5;
}

message Contact {
    uint64 user_id = 1;
    repeated ProjectMetadata projects = 2;
    bool online = 3;
    bool should_notify = 4;
}

message ProjectMetadata {
    uint64 id = 1;
    repeated string worktree_root_names = 3;
    repeated uint64 guests = 4;
}
