> ## Documentation Index
> Fetch the complete documentation index at: https://www.cometchat.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ShortCut Formatter

> Implement message shortcuts using the ShortCutFormatter class in CometChat UI Kit for iOS

## Introduction

The `ShortCutFormatter` class extends the `CometChatTextFormatter` class to provide a mechanism for handling shortcuts within messages. This guide walks you through the process of using `ShortCutFormatter` to implement shortcut extensions in your CometChat application.

***

## Setup

### 1. Create the ShortCutFormatter Class

Define the `ShortCutFormatter` class by extending the `CometChatTextFormatter` class:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    class ShortcutFormatter: CometChatTextFormatter {
        
        // Store fetched shortcuts from the extension
        private var messageShortcuts: [String: String] = [:]
        
        // Store suggestion items for display
        private var shortcuts: [CometChatUIKitSwift.SuggestionItem] = []
    }
    ```
  </Tab>
</Tabs>

### 2. Initialize with Tracking Character

Set the `trackingCharacter` to `'!'` in the initializer:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override init(trackingCharacter: Character) {
        super.init(trackingCharacter: "!")
    }
    ```
  </Tab>
</Tabs>

### 3. Define the Regex Pattern

Set the regular expression for shortcut detection in the `getRegex()` method:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override func getRegex() -> String {
        return "(^|\\s)!\\w+"
    }
    ```
  </Tab>
</Tabs>

### 4. Return the Tracking Character

Define the `getTrackingCharacter()` method to return `'!'` as the shortcut tracking character:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override func getTrackingCharacter() -> Character {
        return "!"
    }
    ```
  </Tab>
</Tabs>

### 5. Implement the Search Method

Override the `search()` method to search for shortcuts based on the entered query:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override func search(string: String, suggestedItems: (([CometChatUIKitSwift.SuggestionItem]) -> ())? = nil) {
        
        // Fetch shortcuts from extension if not already cached
        if messageShortcuts.isEmpty {
            CometChat.callExtension(
                slug: "message-shortcuts",
                type: .get,
                endPoint: "v1/fetch",
                body: nil
            ) { [weak self] extensionResponseData in
                guard let self = self else { return }
                
                if let shortcutData = extensionResponseData?["shortcuts"] as? [String: String] {
                    self.messageShortcuts = shortcutData
                    
                    // Filter shortcuts matching the search string
                    let suggestedItemsList = self.messageShortcuts
                        .filter { $0.key.hasPrefix(string) }
                        .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) }
                    
                    suggestedItems?(suggestedItemsList)
                }
            } onError: { error in
                print("Error occurred while fetching shortcuts: \(error?.errorDescription ?? "Unknown error")")
            }
        } else {
            // Use cached shortcuts
            let suggestedItemsList = messageShortcuts
                .filter { $0.key.hasPrefix(string) }
                .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) }
            
            suggestedItems?(suggestedItemsList)
        }
    }
    ```
  </Tab>
</Tabs>

### 6. Handle Message String Preparation

Implement the `prepareMessageString()` method to convert the base chat message into an attributed string for display:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override func prepareMessageString(
        baseMessage: BaseMessage,
        regexString: String,
        alignment: MessageBubbleAlignment = .left,
        formattingType: FormattingType
    ) -> NSAttributedString {
        let message = (baseMessage as? TextMessage)?.text ?? ""
        return NSAttributedString(string: message)
    }
    ```
  </Tab>
</Tabs>

### 7. Handle Text Tap Events

Override the `onTextTapped()` method if you need to handle tap events on formatted text:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) {
        // Handle tap event on shortcut text
    }
    ```
  </Tab>
</Tabs>

***

## Complete Implementation

Here's the complete `ShortcutFormatter` class:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    import Foundation
    import CometChatSDK
    import CometChatUIKitSwift

    class ShortcutFormatter: CometChatTextFormatter {
        
        // MARK: - Properties
        
        private var messageShortcuts: [String: String] = [:]
        private var shortcuts: [CometChatUIKitSwift.SuggestionItem] = []
        
        // MARK: - Initialization
        
        override init(trackingCharacter: Character) {
            super.init(trackingCharacter: "!")
        }
        
        // MARK: - Override Methods
        
        override func getRegex() -> String {
            return "(^|\\s)!\\w+"
        }
        
        override func getTrackingCharacter() -> Character {
            return "!"
        }
        
        override func search(string: String, suggestedItems: (([CometChatUIKitSwift.SuggestionItem]) -> ())? = nil) {
            
            if messageShortcuts.isEmpty {
                CometChat.callExtension(
                    slug: "message-shortcuts",
                    type: .get,
                    endPoint: "v1/fetch",
                    body: nil
                ) { [weak self] extensionResponseData in
                    guard let self = self else { return }
                    
                    if let shortcutData = extensionResponseData?["shortcuts"] as? [String: String] {
                        self.messageShortcuts = shortcutData
                        
                        let suggestedItemsList = self.messageShortcuts
                            .filter { $0.key.hasPrefix(string) }
                            .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) }
                        
                        suggestedItems?(suggestedItemsList)
                    }
                } onError: { error in
                    print("Error occurred while fetching shortcuts: \(error?.errorDescription ?? "Unknown error")")
                }
            } else {
                let suggestedItemsList = messageShortcuts
                    .filter { $0.key.hasPrefix(string) }
                    .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) }
                
                suggestedItems?(suggestedItemsList)
            }
        }
        
        override func prepareMessageString(
            baseMessage: BaseMessage,
            regexString: String,
            alignment: MessageBubbleAlignment = .left,
            formattingType: FormattingType
        ) -> NSAttributedString {
            let message = (baseMessage as? TextMessage)?.text ?? ""
            return NSAttributedString(string: message)
        }
        
        override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) {
            // Handle tap event on shortcut text
        }
    }
    ```
  </Tab>
</Tabs>

***

## Usage

### 1. Initialize the Formatter

Create an instance of `ShortCutFormatter`:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    let shortcutFormatter = ShortcutFormatter(trackingCharacter: "!")
    ```
  </Tab>
</Tabs>

### 2. Integrate with Message Composer

If you're using the [CometChatMessageComposer](/ui-kit/ios/message-composer) component, integrate the `ShortCutFormatter` to manage shortcut functionalities:

<Tabs>
  <Tab title="Swift">
    ```swift lines theme={null}
    let shortcutFormatter = ShortcutFormatter(trackingCharacter: "!")

    let cometChatMessageComposer = CometChatMessageComposer()
    cometChatMessageComposer.set(textFormatter: [shortcutFormatter])
    ```
  </Tab>
</Tabs>

<Note>
  Ensure to pass and present `cometChatConversationsWithMessages`. If a navigation controller is already in use, utilize the `pushViewController` function instead of directly presenting the view controller.
</Note>

***

## Example

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b/DVg4aTljRFe0drLF/images/23d98cf1-shortcutFormatter-6aa1c5f174fdde4419117170d689943d.png?fit=max&auto=format&n=DVg4aTljRFe0drLF&q=85&s=b786198312cc7c64e0ab97176a18008a" width="1440" height="833" data-path="images/23d98cf1-shortcutFormatter-6aa1c5f174fdde4419117170d689943d.png" />
</Frame>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Mentions Formatter" href="/ui-kit/ios/mentions-formatter-guide">
    Add @mentions with styled tokens and click handling.
  </Card>

  <Card title="Message Composer" href="/ui-kit/ios/message-composer">
    Customize the message input component.
  </Card>

  <Card title="Message List" href="/ui-kit/ios/message-list">
    Display and customize chat messages.
  </Card>

  <Card title="Message Template" href="/ui-kit/ios/message-template">
    Define custom message bubble structures.
  </Card>
</CardGroup>

***
