Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
ColumnLimit: 100
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterControlStatement: Always
AfterFunction: true
AfterNamespace: true
AfterStruct: true
Expand All @@ -20,5 +19,5 @@ PointerAlignment: Left
SpaceAfterCStyleCast: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
AlignConsecutiveAssignments: false
AlignConsecutiveAssignments: None
AlignTrailingComments: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,6 @@ core
src/*
!src/*.cpp
!src/*.hpp
!src/**
!src/**/*.cpp
!src/**/*.hpp
20 changes: 14 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)

project(cpp-workspace VERSION 0.2.0 LANGUAGES CXX)
project(cpp-workspace VERSION 0.2.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -12,11 +12,19 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

add_executable(cpp-workspace-app
src/main.cpp
src/ollama_client.cpp
src/progress_spinner.cpp
src/user-interface.cpp
src/text-utils.cpp
src/main.cpp
src/interface/progress_spinner.cpp
src/interface/user-interface.cpp
src/ollama/ollama_client.cpp
src/utils/text-utils.cpp
)

target_include_directories(cpp-workspace-app
PRIVATE
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/interface
${CMAKE_SOURCE_DIR}/src/ollama
${CMAKE_SOURCE_DIR}/src/utils
)

find_package(fmt REQUIRED)
Expand Down
File renamed without changes.
File renamed without changes.
85 changes: 83 additions & 2 deletions src/user-interface.cpp → src/interface/user-interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,88 @@ void UserInterface::print_args_noninteractive(const std::string& model, const st
printf("\n");
}

void UserInterface::print_model_list(const std::vector<std::string>& models) {
std::string buffer;
buffer += "\n🛈 Select a model from the list below:\n";
for (size_t i = 0; i < models.size(); i += 1) {
buffer += "[" + std::to_string(i) + "] " + models[i] + "\n";
}

this->print(buffer, UserInterface::MESSAGE_TYPE_NORMAL);
}

void UserInterface::print_model_list_noninteractive(const std::vector<std::string>& models) {
printf("\n🛈 Select a model from the list below:\n");
for (size_t i = 0; i < models.size(); i += 1) {
printf("[%zu] %s\n", i, models[i].c_str());
}
}

void UserInterface::select_model(const std::vector<std::string>& models, std::string* model) {
int index{};

if (models.size() == 0) {
this->print_error("There are no available models to select from.\n");
exit(1);
}

this->request_redraw();

this->input_buffer.clear();
int ch;

while ((ch = getch()) != '\n') {
if (ch == KEY_BACKSPACE || ch == 127) {
if (!input_buffer.empty()) {
input_buffer.pop_back();
input_cursor_x--;
this->request_redraw();
}
} else if (ch != ERR && isprint(ch)) {
if (input_buffer.length() < COLS - 40) { // Leave room for prompt
input_buffer.push_back(ch);
input_cursor_x++;
this->request_redraw();
}
}
}

if (this->input_buffer == "q" || this->input_buffer == "Q") {
this->end_session(EXIT_SUCCESS);
}

index = stoi(this->input_buffer);

if (index < 0 || index >= models.size()) {
std::string message = std::format("Model index %d does not exist.\n", index);
this->print_error(message);
this->select_model(models, model);
} else {
*model = models[index];
}
}

void UserInterface::select_model_noninteractive(const std::vector<std::string>& models,
std::string* model) {
int index{};
int read_result{};

if (models.size() == 0) {
fprintf(stderr, "There are no available models to select from.\n");
exit(1);
}

while (read_result != 1 || index < 0 || index >= models.size()) {
if (index < 0 || index >= models.size()) {
fprintf(stderr, "Model index %d does not exist.\n", index);
}
printf("Model index: ");
read_result = scanf("%d", &index);
}

*model = models[index];
}

bool UserInterface::next_prompt(std::string* prompt) {
bool done = false;

Expand Down Expand Up @@ -374,8 +456,7 @@ void UserInterface::draw_output_area() {

// Render from bottom to top (reverse order)
for (auto line_it = display_lines.rbegin(); line_it != display_lines.rend(); ++line_it) {
if (current_line <= layout.output_y)
break;
if (current_line <= layout.output_y) break;

if (type == UserInterface::MESSAGE_TYPE_ERROR) {
wattron(stdscr, COLOR_PAIR(ERROR_PAIR) | A_BOLD);
Expand Down
30 changes: 29 additions & 1 deletion src/user-interface.hpp → src/interface/user-interface.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "text-utils.hpp"
#include "utils/text-utils.hpp"
#include <atomic>
#include <condition_variable>
#include <functional>
Expand Down Expand Up @@ -221,6 +221,7 @@ class UserInterface {
*/
void print_args(const std::string& model, const std::string& prompt, bool stream,
bool interactive, bool dark_theme);

/**
* Static version of print_args() for non-interactive mode.
* Outputs arguments to stdout instead of the UI.
Expand All @@ -233,6 +234,33 @@ class UserInterface {
static void print_args_noninteractive(const std::string& model, const std::string& prompt,
bool stream, bool interactive, bool dark_theme);

/**
* Prints available models and their corresponding indexes for selection.
* @param models The list of available local models.
*/
void print_model_list(const std::vector<std::string>& models);

/**
* Static version of print_model_list() for non-interactive mode.
* @param models The list of available local models.
*/
static void print_model_list_noninteractive(const std::vector<std::string>& models);

/**
* Prompts for user input to select a model form the list of available local models.
* @param models The list of available local models.
* @param model Pointer to a std::string to receive the user input.
*/
void select_model(const std::vector<std::string>& models, std::string* model);

/**
* Static version of the select_model() for non-interactive mode.
* @param models The list of available local models.
* @param model Pointer to a std::string to receive the user input.
*/
static void select_model_noninteractive(const std::vector<std::string>& models,
std::string* model);

/**
* Waits for and retrieves the next user input prompt (interactive mode).
* Blocks until the user presses Enter and a prompt is available.
Expand Down
25 changes: 22 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "ollama_client.hpp"
#include "user-interface.hpp"
#include "interface/user-interface.hpp"
#include "ollama/ollama_client.hpp"
#include <iostream>
#include <unistd.h>

Expand Down Expand Up @@ -69,7 +69,26 @@ int main(int argc, const char* argv[]) {

OllamaClient client = OllamaClient(&ui);

client.query_model_list();
std::vector<std::string> models = client.query_model_list();
bool force_model_selection = true;
for (size_t i = 0; i < models.size(); i += 1) {
if (models[i] == model) {
force_model_selection = false;
}
}

if (force_model_selection == true) {
if (interactive == true) {
ui.print_model_list(models);
ui.select_model(models, &model);
ui.print_args(model, prompt, stream, interactive, dark_theme);
} else {
UserInterface::print_model_list_noninteractive(models);
UserInterface::select_model_noninteractive(models, &model);
UserInterface::print_args_noninteractive(model, prompt, stream, interactive,
dark_theme);
}
}

struct OllamaPromptConfig config;
config.model = model;
Expand Down
9 changes: 8 additions & 1 deletion src/ollama_client.cpp → src/ollama/ollama_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ void OllamaClient::query_model(OllamaPromptConfig config) {
*
* @see OllamaPromptConfig for model information structure
*/
void OllamaClient::query_model_list() {
std::vector<std::string> OllamaClient::query_model_list() {
this->init_curl();

this->spinner->start();
Expand Down Expand Up @@ -425,6 +425,7 @@ void OllamaClient::query_model_list() {
curl_slist_free_all(this->headers);
this->headers = nullptr;

std::vector<std::string> models;
std::string message{};
if (result != CURLE_OK) {
message = std::format("CURL error: {}\n", curl_easy_strerror(result));
Expand Down Expand Up @@ -484,6 +485,10 @@ void OllamaClient::query_model_list() {
? std::to_string(model["size"].get<long long>() / 1024 / 1024) + " Mb"
: "size unknown";

if (name != "unknown") {
models.push_back(name);
}

message = std::format("{}\t ({}) \t{}\n", modified_at, size, name);
if (this->ui->is_running() == false) {
printf("%s", message.c_str());
Expand All @@ -502,4 +507,6 @@ void OllamaClient::query_model_list() {
this->ui->end_session(EXIT_FAILURE);
}
}

return models;
}
7 changes: 4 additions & 3 deletions src/ollama_client.hpp → src/ollama/ollama_client.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "progress_spinner.hpp"
#include "user-interface.hpp"
#include "interface/progress_spinner.hpp"
#include "interface/user-interface.hpp"
#include <curl/curl.h>
#include <iostream>

Expand Down Expand Up @@ -199,6 +199,7 @@ class OllamaClient {
* each model with its information formatted as a table.
*
* @note On error, displays an error message and exits or ends the session.
* @returns The list of available local models.
*/
void query_model_list();
std::vector<std::string> query_model_list();
};
File renamed without changes.
File renamed without changes.
19 changes: 18 additions & 1 deletion tools/shell/format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@

set -euo pipefail

clang-format src/* -i -Werror
# Change to repo root (handles running from any directory)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"

echo "Running from: $(pwd)"
echo "---"
echo "Directory structure:"
ls -la src/
echo "---"
echo "All .cpp and .hpp files:"
find src -type f \( -name "*.cpp" -o -name "*.hpp" \)
echo "---"

find src -type f \( -name "*.cpp" -o -name "*.hpp" \) -exec clang-format -i -Werror {} +

cppcheck --std=c++20 \
--enable=all \
--error-exitcode=1 \
--suppress=missingIncludeSystem \
--suppress=unusedLabel \
-I src/ \
-I src/interface \
-I src/ollama \
-I src/utils \
src/
Loading