|
| 1 | +/* |
| 2 | + * Copyright (C) 2016-2017, Egor Pugin |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +#include "build.h" |
| 18 | + |
| 19 | +#include <config.h> |
| 20 | +#include <database.h> |
| 21 | + |
| 22 | +#include <readline/readline.h> |
| 23 | +#include <readline/history.h> |
| 24 | + |
| 25 | +#include <iostream> |
| 26 | + |
| 27 | +#include <conio.h> |
| 28 | + |
| 29 | +char **character_name_completion(const char *, int, int); |
| 30 | +char *character_name_generator(const char *, int); |
| 31 | +int old_string = 0; |
| 32 | +String old_s; |
| 33 | + |
| 34 | +int my_getc(FILE *f) |
| 35 | +{ |
| 36 | + auto c = _getch(); |
| 37 | + old_string = !is_valid_project_path_symbol(c) && |
| 38 | + c != '\b' && c != '-'; |
| 39 | + if (!old_string) |
| 40 | + { |
| 41 | + old_s = rl_line_buffer; |
| 42 | + if (c != '\b') |
| 43 | + old_s += c; |
| 44 | + else if (!old_s.empty()) |
| 45 | + old_s.resize(old_s.size() - 1); |
| 46 | + } |
| 47 | + return c; |
| 48 | +} |
| 49 | + |
| 50 | +void command_init(const Strings &args) |
| 51 | +{ |
| 52 | + String project_type = "e"; |
| 53 | + Project p; |
| 54 | + p.name = fs::current_path().filename().string(); |
| 55 | + |
| 56 | + auto readline = [](String &d) |
| 57 | + { |
| 58 | + String s; |
| 59 | + std::getline(std::cin, s); |
| 60 | + if (!s.empty()) |
| 61 | + d = s; |
| 62 | + }; |
| 63 | + |
| 64 | + // interactive mode |
| 65 | + if (args.empty()) |
| 66 | + { |
| 67 | + std::cout << "Enter project name [" << p.name << "]: "; |
| 68 | + readline(p.name); |
| 69 | + std::cout << "Enter project type (e - executable, l - library) [" << project_type << "]: "; |
| 70 | + readline(project_type); |
| 71 | + std::cout << "Add some dependencies (y/n) [n]: "; |
| 72 | + String add_deps; |
| 73 | + readline(add_deps); |
| 74 | + if (add_deps[0] == 'y') |
| 75 | + { |
| 76 | + std::cout << "Start entering dependencies' names. You could use TAB to list matching packages.\n"; |
| 77 | + |
| 78 | + rl_attempted_completion_function = character_name_completion; |
| 79 | + rl_completion_query_items = 50; |
| 80 | + //rl_editing_mode = 0; // vi mode |
| 81 | + //rl_getc_function = my_getc; |
| 82 | + //rl_variable_bind("show-mode-in-prompt", "1"); |
| 83 | + while (auto buffer = ::readline("> ")) |
| 84 | + { |
| 85 | + printf("You entered: %s\n", buffer); |
| 86 | + if (*buffer) |
| 87 | + add_history(buffer); |
| 88 | + free(buffer); |
| 89 | + } |
| 90 | + } |
| 91 | + } |
| 92 | + else |
| 93 | + { |
| 94 | + |
| 95 | + } |
| 96 | + |
| 97 | + if (project_type[0] == 'l') |
| 98 | + p.type = ProjectType::Library; |
| 99 | + |
| 100 | + boost::system::error_code ec; |
| 101 | + auto root = fs::current_path(); |
| 102 | + |
| 103 | + // checks first |
| 104 | + if (fs::exists(root / p.name) || |
| 105 | + fs::exists(root / p.name / "src") || |
| 106 | + fs::exists(root / p.name / "include") || |
| 107 | + fs::exists(root / p.name / "include" / p.name) || |
| 108 | + fs::exists(root / p.name / "include" / p.name / (p.name + ".h")) || |
| 109 | + fs::exists(root / p.name / "src" / (p.name + ".cpp")) || |
| 110 | + 0) |
| 111 | + throw std::runtime_error("One of the fs objects to be created already exist"); |
| 112 | + |
| 113 | + // create, no checks |
| 114 | + fs::create_directories(root / p.name / "src"); |
| 115 | + if (p.type == ProjectType::Library) |
| 116 | + { |
| 117 | + fs::create_directories(root / p.name / "include" / p.name); |
| 118 | + write_file(root / p.name / "src" / (p.name + ".cpp"), "#include <" + p.name + "/" + p.name + ".h>\n\n"); |
| 119 | + write_file(root / p.name / "include" / p.name / (p.name + ".h"), "//#include <something>\n\n"); |
| 120 | + } |
| 121 | + else |
| 122 | + { |
| 123 | + write_file(root / p.name / "src" / (p.name + ".cpp"), "//#include <something>\n\n" |
| 124 | + "int main(int argc, char **argv)\n{\n return 0;\n}\n"); |
| 125 | + } |
| 126 | + |
| 127 | + p.root_directory = p.name; |
| 128 | + |
| 129 | + yaml y; |
| 130 | + if (!fs::exists(CPPAN_FILENAME)) |
| 131 | + { |
| 132 | + y = p.save(); |
| 133 | + } |
| 134 | + else |
| 135 | + { |
| 136 | + auto orig = load_yaml_config(path(CPPAN_FILENAME)); |
| 137 | + Config c; |
| 138 | + c.allow_relative_project_names = true; |
| 139 | + //c.allow_local_dependencies = true; |
| 140 | + c.load(orig); |
| 141 | + auto &projects = c.getProjects(); |
| 142 | + if (projects.find(p.name) != projects.end()) |
| 143 | + throw std::runtime_error("Project " + p.name + " already exists in the config"); |
| 144 | + projects[p.name] = p; |
| 145 | + y = c.save(); |
| 146 | + orig["projects"] = y["projects"]; |
| 147 | + y = orig; |
| 148 | + } |
| 149 | + dump_yaml_config(CPPAN_FILENAME, y); |
| 150 | + |
| 151 | + build(root); |
| 152 | +} |
| 153 | + |
| 154 | +char ** |
| 155 | +character_name_completion(const char *text, int start, int end) |
| 156 | +{ |
| 157 | + rl_attempted_completion_over = 1; |
| 158 | + rl_completion_suppress_append = 1; |
| 159 | + if (*text == 0 && start) |
| 160 | + return nullptr; |
| 161 | + return rl_completion_matches(text, character_name_generator); |
| 162 | +} |
| 163 | + |
| 164 | +char * |
| 165 | +character_name_generator(const char *text, int state) |
| 166 | +{ |
| 167 | + static std::vector<String> spkgs; |
| 168 | + static size_t i; |
| 169 | + static String t; |
| 170 | + |
| 171 | + auto read_packages = [](const String &s) |
| 172 | + { |
| 173 | + auto &pdb = getPackagesDatabase(); |
| 174 | + auto pkgs = pdb.getMatchingPackages<std::unordered_set>(s); |
| 175 | + std::vector<String> spkgs; |
| 176 | + spkgs.reserve(pkgs.size()); |
| 177 | + for (auto &pkg : pkgs) |
| 178 | + spkgs.push_back(pkg.toString()); |
| 179 | + return spkgs; |
| 180 | + }; |
| 181 | + |
| 182 | + auto read_versions = [](const String &pkg) |
| 183 | + { |
| 184 | + auto &pdb = getPackagesDatabase(); |
| 185 | + auto versions = pdb.getVersionsForPackage(pkg); |
| 186 | + std::vector<String> spkgs; |
| 187 | + spkgs.reserve(versions.size()); |
| 188 | + bool has_versions = false; |
| 189 | + for (auto &v : versions) |
| 190 | + { |
| 191 | + spkgs.push_back(pkg + "-" + v.toString()); |
| 192 | + if (v.isVersion()) |
| 193 | + { |
| 194 | + has_versions = true; |
| 195 | + v.patch = -1; |
| 196 | + spkgs.push_back(pkg + "-" + v.toAnyVersion()); |
| 197 | + v.minor = -1; |
| 198 | + spkgs.push_back(pkg + "-" + v.toAnyVersion()); |
| 199 | + } |
| 200 | + } |
| 201 | + if (has_versions) |
| 202 | + spkgs.push_back(pkg); // self, * version |
| 203 | + return spkgs; |
| 204 | + }; |
| 205 | + |
| 206 | + if (!state) |
| 207 | + { |
| 208 | + i = -1; |
| 209 | + t = old_string ? old_s : text; |
| 210 | + spkgs = read_packages(t); |
| 211 | + if (spkgs.size() == 1) |
| 212 | + spkgs = read_versions(spkgs[0]); |
| 213 | + } |
| 214 | + |
| 215 | + while (++i < spkgs.size()) |
| 216 | + { |
| 217 | + if (spkgs[i].find(t) != -1) |
| 218 | + { |
| 219 | + return strdup(spkgs[i].c_str()); |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + return nullptr; |
| 224 | +} |
0 commit comments