From 40a06545c02e31f6ff614e033ea2467dffe3a2a8 Mon Sep 17 00:00:00 2001 From: Shubh942 <93862397+Shubh942@users.noreply.github.com> Date: Sat, 10 Aug 2024 22:24:16 +0530 Subject: [PATCH 1/4] feat: added coding screen for real code experience. --- webapp/package-lock.json | 90 +++++++++++++++++++ webapp/package.json | 2 + webapp/src/App.jsx | 4 +- .../src/components/MainScreen/MainScreen.jsx | 13 ++- webapp/src/context/DataContext.jsx | 6 ++ webapp/src/pages/Debug/Debug.jsx | 2 +- 6 files changed, 113 insertions(+), 4 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 1dc71e5..f99464c 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -8,7 +8,9 @@ "name": "a_main_gdbui", "version": "0.0.0", "dependencies": { + "@monaco-editor/react": "^4.6.0", "axios": "^1.7.2", + "monaco-themes": "^0.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^5.2.1", @@ -2843,6 +2845,30 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@monaco-editor/loader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", + "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", + "dependencies": { + "state-local": "^1.0.6" + }, + "peerDependencies": { + "monaco-editor": ">= 0.21.0 < 1" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", + "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "dependencies": { + "@monaco-editor/loader": "^1.4.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -8286,6 +8312,11 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-plist": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fast-plist/-/fast-plist-0.1.3.tgz", + "integrity": "sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A==" + }, "node_modules/fast-xml-parser": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", @@ -11472,6 +11503,20 @@ "ufo": "^1.5.3" } }, + "node_modules/monaco-editor": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz", + "integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==", + "peer": true + }, + "node_modules/monaco-themes": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/monaco-themes/-/monaco-themes-0.4.4.tgz", + "integrity": "sha512-Hbb9pvRrpSi0rZezcB/IOdQnpx10o55Lx4zFdRAAVpFMa1HP7FgaqEZdKffb4ovd90fETCixeFO9JPYFMAq+TQ==", + "dependencies": { + "fast-plist": "^0.1.3" + } + }, "node_modules/mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", @@ -13723,6 +13768,11 @@ "node": ">=8" } }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -17038,6 +17088,22 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@monaco-editor/loader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", + "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", + "requires": { + "state-local": "^1.0.6" + } + }, + "@monaco-editor/react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", + "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "requires": { + "@monaco-editor/loader": "^1.4.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -21052,6 +21118,11 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-plist": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fast-plist/-/fast-plist-0.1.3.tgz", + "integrity": "sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A==" + }, "fast-xml-parser": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", @@ -23434,6 +23505,20 @@ "ufo": "^1.5.3" } }, + "monaco-editor": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz", + "integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==", + "peer": true + }, + "monaco-themes": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/monaco-themes/-/monaco-themes-0.4.4.tgz", + "integrity": "sha512-Hbb9pvRrpSi0rZezcB/IOdQnpx10o55Lx4zFdRAAVpFMa1HP7FgaqEZdKffb4ovd90fETCixeFO9JPYFMAq+TQ==", + "requires": { + "fast-plist": "^0.1.3" + } + }, "mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", @@ -25101,6 +25186,11 @@ } } }, + "state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", diff --git a/webapp/package.json b/webapp/package.json index b9b5dd6..1839b38 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -13,7 +13,9 @@ "coverage": "vitest run --coverage" }, "dependencies": { + "@monaco-editor/react": "^4.6.0", "axios": "^1.7.2", + "monaco-themes": "^0.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^5.2.1", diff --git a/webapp/src/App.jsx b/webapp/src/App.jsx index 2177c0f..4145449 100644 --- a/webapp/src/App.jsx +++ b/webapp/src/App.jsx @@ -8,10 +8,10 @@ import MemoryMap from "./components/GdbComponents/MemoryMap/MemoryMap"; import BreakPoints from "./components/GdbComponents/BreakPoints/BreakPoints"; import Footer from "./components/Footer/Footer"; import Header from "./components/Header/Header"; +import { DataState } from "./context/DataContext"; const App = () => { - const [isDarkMode, setDarkMode] = useState("dark"); - const [dark, setDark] = useState(false); + const { setDark, dark, isDarkMode, setDarkMode } = DataState(); const toggleDarkMode = () => { setDarkMode((isDarkMode) => (isDarkMode === "dark" ? "light" : "dark")); diff --git a/webapp/src/components/MainScreen/MainScreen.jsx b/webapp/src/components/MainScreen/MainScreen.jsx index 7efe08c..b06b112 100644 --- a/webapp/src/components/MainScreen/MainScreen.jsx +++ b/webapp/src/components/MainScreen/MainScreen.jsx @@ -1,11 +1,22 @@ import React from "react"; import "./MainScreen.css"; +import Editor from "@monaco-editor/react"; +import { DataState } from "../../context/DataContext"; const MainScreen = () => { + const { isDarkMode } = DataState(); return (
MainScreen -
+
+ +
); }; diff --git a/webapp/src/context/DataContext.jsx b/webapp/src/context/DataContext.jsx index ae79b43..fd4df8e 100644 --- a/webapp/src/context/DataContext.jsx +++ b/webapp/src/context/DataContext.jsx @@ -10,6 +10,8 @@ import axios from "axios"; export const DataContext = createContext(); export const DataProvider = ({ children }) => { + const [isDarkMode, setDarkMode] = useState("dark"); + const [dark, setDark] = useState(false); const [refresh, setRefresh] = useState(false); const [stack, setStack] = useState([]); const [functions, setFunctions] = useState([]); @@ -44,6 +46,10 @@ export const DataProvider = ({ children }) => { setInfoBreakpointData, memoryMap, setMemoryMap, + isDarkMode, + setDarkMode, + dark, + setDark, }} > {children} diff --git a/webapp/src/pages/Debug/Debug.jsx b/webapp/src/pages/Debug/Debug.jsx index 43cf1b4..053fedd 100644 --- a/webapp/src/pages/Debug/Debug.jsx +++ b/webapp/src/pages/Debug/Debug.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import "./Debug.css"; import Header from "../../components/Header/Header"; import DebugHeader from "../../components/DebugHeader/DebugHeader"; From 06600a26bfbbbe221ab2cc7c9ae404ff0c1ee46f Mon Sep 17 00:00:00 2001 From: Shubh942 <93862397+Shubh942@users.noreply.github.com> Date: Sun, 11 Aug 2024 14:43:07 +0530 Subject: [PATCH 2/4] feat: added functionality of terminal output. --- .../src/components/Terminal/TerminalComp.jsx | 29 ++++++++++++++++--- webapp/src/main.jsx | 9 ++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/webapp/src/components/Terminal/TerminalComp.jsx b/webapp/src/components/Terminal/TerminalComp.jsx index 7fa2b1f..6b1c745 100644 --- a/webapp/src/components/Terminal/TerminalComp.jsx +++ b/webapp/src/components/Terminal/TerminalComp.jsx @@ -1,22 +1,43 @@ -import React from "react"; +import React, { useState } from "react"; import { ReactTerminal } from "react-terminal"; - +import axios from "axios"; import "./Terminal.css"; const TerminalComp = () => { + const [output, setOutput] = useState(""); + + const handleCommand = async (command) => { + try { + const { data } = await axios.post("http://127.0.0.1:10000/gdb_command", { + command: command, + name: "program", + }); + return data["result"]; + } catch (error) { + return "Error executing command"; + } + }; + return (
- TerminalComp { + return await handleCommand(command); + }, + }} + defaultHandler={async (command) => { + return await handleCommand(command); + }} />
); diff --git a/webapp/src/main.jsx b/webapp/src/main.jsx index 446bd5f..76403de 100644 --- a/webapp/src/main.jsx +++ b/webapp/src/main.jsx @@ -3,15 +3,18 @@ import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; import { DataProvider } from "./context/DataContext"; +import { TerminalContextProvider } from "react-terminal"; import App from "./App"; import "./index.css"; ReactDOM.render( - - - + + + + + , document.getElementById("root") From 9a6b249e21f122160f215f4764f6dc5c93becffe Mon Sep 17 00:00:00 2001 From: Shubh942 <93862397+Shubh942@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:08:05 +0530 Subject: [PATCH 3/4] enhancment: connect every icon with server according their orientation --- gdbui_server/main.py | 6 +- .../components/DebugHeader/DebugHeader.css | 1 + .../components/DebugHeader/DebugHeader.jsx | 78 ++++++++++++++++--- webapp/src/components/Functions/Functions.css | 4 +- .../src/components/MainScreen/MainScreen.jsx | 2 +- .../src/components/Terminal/TerminalComp.jsx | 35 ++++++--- webapp/src/context/DataContext.jsx | 11 ++- 7 files changed, 111 insertions(+), 26 deletions(-) diff --git a/gdbui_server/main.py b/gdbui_server/main.py index 6539127..a6d4d9e 100644 --- a/gdbui_server/main.py +++ b/gdbui_server/main.py @@ -235,17 +235,17 @@ def get_locals(): start_gdb_session(f'{file}') try: - result = execute_gdb_command("info locals") + result = execute_gdb_command("info functions") response = { 'success': True, 'result': result, - 'code': "execute_gdb_command('info locals')" + 'code': "execute_gdb_command('info functions')" } except Exception as e: response = { 'success': False, 'error': str(e), - 'code': "execute_gdb_command('info locals')" + 'code': "execute_gdb_command('info functions')" } return jsonify(response) diff --git a/webapp/src/components/DebugHeader/DebugHeader.css b/webapp/src/components/DebugHeader/DebugHeader.css index 1743f99..9fc235f 100644 --- a/webapp/src/components/DebugHeader/DebugHeader.css +++ b/webapp/src/components/DebugHeader/DebugHeader.css @@ -75,6 +75,7 @@ body { } .icon { transition: border 0.1s ease-in-out, padding 0.1s ease-in-out; + cursor: pointer; } .icon:hover { diff --git a/webapp/src/components/DebugHeader/DebugHeader.jsx b/webapp/src/components/DebugHeader/DebugHeader.jsx index 6347409..0f3b499 100644 --- a/webapp/src/components/DebugHeader/DebugHeader.jsx +++ b/webapp/src/components/DebugHeader/DebugHeader.jsx @@ -13,23 +13,83 @@ import { DataState } from "../../context/DataContext"; import "./DebugHeader.css"; const DebugHeader = () => { - const { refresh, setRefresh } = DataState(); + const { + refresh, + setRefresh, + setTerminalOutput, + setCommandPress, + commandPress, + } = DataState(); + + const handleRun = (command) => { + console.log("clicked"); + setCommandPress(!commandPress); + setTerminalOutput(command); + }; return (
- - + { + handleRun("previous"); + }} + /> + { + handleRun("next"); + }} + />
- - - - - - + { + handleRun("run"); + }} + /> + { + handleRun("continue"); + }} + /> + { + handleRun("stop"); + }} + /> + { + handleRun("step"); + }} + /> + { + handleRun("finish"); + }} + /> + { + handleRun("step-out"); + }} + />
diff --git a/webapp/src/components/Functions/Functions.css b/webapp/src/components/Functions/Functions.css index d31aae6..89146f6 100644 --- a/webapp/src/components/Functions/Functions.css +++ b/webapp/src/components/Functions/Functions.css @@ -6,6 +6,7 @@ align-items: center; gap: 10px; border: 1px solid var(--Gray-2, #4f4f4f); + /* background: #1e1e1e; */ } .functions-heading { @@ -22,13 +23,14 @@ display: flex; padding: 10px; height: 87vh; + max-width: 20vw; flex-direction: column; align-items: flex-start; gap: 11px; flex-shrink: 0; border: 1px solid var(--Gray-2, #4f4f4f); overflow-y: scroll; - overflow-x: hidden; + overflow-x: scroll; } .functions a { display: block; /* Ensure the anchor tags are block-level elements */ diff --git a/webapp/src/components/MainScreen/MainScreen.jsx b/webapp/src/components/MainScreen/MainScreen.jsx index b06b112..2fc46ba 100644 --- a/webapp/src/components/MainScreen/MainScreen.jsx +++ b/webapp/src/components/MainScreen/MainScreen.jsx @@ -12,7 +12,7 @@ const MainScreen = () => { diff --git a/webapp/src/components/Terminal/TerminalComp.jsx b/webapp/src/components/Terminal/TerminalComp.jsx index 6b1c745..a531b40 100644 --- a/webapp/src/components/Terminal/TerminalComp.jsx +++ b/webapp/src/components/Terminal/TerminalComp.jsx @@ -1,15 +1,20 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { ReactTerminal } from "react-terminal"; import axios from "axios"; import "./Terminal.css"; +import { DataState } from "../../context/DataContext"; const TerminalComp = () => { + const { terminalOutput, commandPress } = DataState(); const [output, setOutput] = useState(""); + const terminalRef = useRef("null"); - const handleCommand = async (command) => { + const handleCommand = async (command, ...args) => { + const fullCommand = [command, ...args].join(" "); + console.log("Full Command:", fullCommand); try { const { data } = await axios.post("http://127.0.0.1:10000/gdb_command", { - command: command, + command: fullCommand, name: "program", }); return data["result"]; @@ -18,9 +23,24 @@ const TerminalComp = () => { } }; + const defaultHandler = async (command, ...args) => { + const result = await handleCommand(command, ...args); + setOutput(result); + return result; + }; + + useEffect(() => { + console.log(terminalOutput); + if (terminalOutput) { + console.log(terminalOutput); + defaultHandler(terminalOutput); + } + }, [commandPress]); + return (
{ }, }} theme="my-custom-theme" - commands={{ - myCommand: async (command) => { - return await handleCommand(command); - }, - }} - defaultHandler={async (command) => { - return await handleCommand(command); - }} + defaultHandler={defaultHandler} />
); diff --git a/webapp/src/context/DataContext.jsx b/webapp/src/context/DataContext.jsx index fd4df8e..7bb7f7f 100644 --- a/webapp/src/context/DataContext.jsx +++ b/webapp/src/context/DataContext.jsx @@ -5,7 +5,6 @@ import React, { useCallback, useContext, } from "react"; -import axios from "axios"; export const DataContext = createContext(); @@ -17,6 +16,8 @@ export const DataProvider = ({ children }) => { const [functions, setFunctions] = useState([]); const [infoBreakpointData, setInfoBreakpointData] = useState(""); const [memoryMap, setMemoryMap] = useState(""); + const [terminalOutput, setTerminalOutput] = useState(""); + const [commandPress, setCommandPress] = useState(true); const fetchData = useCallback(async () => { if (refresh) { @@ -33,6 +34,10 @@ export const DataProvider = ({ children }) => { fetchData(); }, [fetchData]); + const runCommandInTerminal = (command) => { + setTerminalOutput(command); + }; + return ( { setDarkMode, dark, setDark, + terminalOutput, + setCommandPress, + commandPress, + setTerminalOutput, }} > {children} From 4a1968cbed0ab55217c2c511f35c5a439ac2a9ce Mon Sep 17 00:00:00 2001 From: Shubh Mehta <93862397+Shubh942@users.noreply.github.com> Date: Sun, 25 Aug 2024 12:10:10 +0530 Subject: [PATCH 4/4] Update README.md --- README.md | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fa571d..0dac157 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,143 @@ # GDB-UI -GDB stands for GNU Debugger. It's a powerful and popular debugger for various programming languages, including C, C++, Ada, and others. It allows developers to observe what a program is doing while it's running. This is particularly useful when debugging to find and fix problems in the code. +**GDB-UI** is a user-friendly interface built for the GNU Debugger (GDB), providing a modern web-based UI for debugging your applications. It allows developers to monitor program execution, inspect variables, set breakpoints, and more, all through an intuitive web application. + +**GitHub Repository:** [c2siorg/GDB-UI](https://github.com/c2siorg/GDB-UI) + +## Project Overview + +GDB-UI simplifies the debugging process by integrating the powerful features of GDB with a sleek and easy-to-use web interface. This project is particularly useful for developers working with languages like C, C++, and Ada. The interface offers a more accessible and visual approach to debugging, making it easier to identify and fix issues in your code. + +## Getting Started + +### Docker Setup + +The quickest way to get started with GDB-UI is by using Docker. A `docker-compose.yml` file is provided to handle the entire setup. + +1. Ensure Docker and Docker Compose are installed on your machine. +2. Run the following command in your terminal: + + ```sh + docker-compose up + ``` + +This command will build and start both the frontend and backend services, making the application available at [http://localhost:3000](http://localhost:3000) (or your specified port). + +### Manual Setup + +If you prefer a manual setup or are unable to use Docker, follow these steps: + +#### Prerequisites + +- **Node.js:** Version 18 +- **Python:** Version 3.10 + +#### Frontend Setup (React) + +1. Navigate to the `webapp` directory: + + ```sh + cd webapp + ``` + +2. Install the necessary dependencies: + + ```sh + npm install + ``` + +3. Start the development server: + + ```sh + npm run dev + ``` + +#### Backend Setup (Python Server) + +1. Navigate to the `gdbui_server` directory: + + ```sh + cd gdbui_server + ``` + +2. Install the required Python packages: + + ```sh + pip install -r requirements.txt + ``` + +3. Run the backend server: + + ```sh + python main.py + ``` + +## Running Tests + +### Frontend Tests (Vite) + +To run the frontend tests, follow these steps: + +1. Navigate to the `webapp` directory: + + ```sh + cd webapp + ``` + +2. Run the tests using Vite: + + ```sh + npm run test + ``` + +### Backend Tests + +To run the backend tests, use the following procedure: + +1. Ensure your Python environment is set up as described in the manual setup. +2. Navigate to the `gdbui_server` directory: + + ```sh + cd gdbui_server + ``` + +3. Run the tests using the `unittest` module: + + ```sh + python -m unittest discover -s tests + ``` + +## Contributing + +We welcome contributions from the community! To get started: + +1. **Fork the repository at** [c2siorg/GDB-UI](https://github.com/c2siorg/GDB-UI). +2. **Clone your fork:** + + ```sh + git clone https://github.com/your-username/GDB-UI.git + ``` + +3. **Create a new branch for your feature or bugfix:** + + ```sh + git checkout -b feature-name + ``` + +4. **Make your changes and commit them:** + + ```sh + git commit -m "Description of your changes" + ``` + +5. **Push your branch to your fork:** + + ```sh + git push origin feature-name + ``` + +6. **Open a pull request** on the main repository. + +**Please ensure your code adheres to our coding standards and is thoroughly tested before submitting your pull request.** + +