10
10
11
11
namespace po = boost::program_options;
12
12
13
+ /* *
14
+ * Compares the given input command against binaries found in the system path, applying, if enabled a heuristic
15
+ * based on the difference in length and character similarities between the input command and system binaries,
16
+ * which filters those whose difference with the input command exceeds a threshold.
17
+ * Calculates the word distances with the Damerau-Leveshtein algorithm and suggests the closest matches.
18
+ *
19
+ * @param vm Boost program options variables map that holds command line options.
20
+ * @param inputCommand The command entered by the user, which needs to be matched or corrected.
21
+ * @param settings The settings object containing configuration such as system path variables and heuristics for matching.
22
+ * @return true if similar commands are found, otherwise false if no suggestions can be made.
23
+ */
24
+ bool suggestCommands (const po::variables_map vm, std::string inputCommand, Settings settings) {
25
+ spdlog::info (" Printing content of system path vector" );
26
+
27
+ // If verbose mode enabled print the content of the system path vector
28
+ if (vm.count (" v" ))
29
+ CommonUtils::printVector (settings.getSystemPathVariablePaths ());
30
+
31
+ // Moving system path to a new data structure
32
+ std::set<std::string> systemPathVariableSet;
33
+ for (const auto &entry : settings.getSystemPathVariablePaths ()) {
34
+ std::vector<std::string> filesInPath = CommonUtils::getListOfFilesInPath (entry, false , true );
35
+ systemPathVariableSet.insert (filesInPath.begin (), filesInPath.end ());
36
+ }
37
+
38
+ spdlog::info (" Printing content of system path set" );
39
+
40
+ // If verbose mode enabled print the set
41
+ if (vm.count (" v" ))
42
+ CommonUtils::printSet (systemPathVariableSet);
43
+
44
+ spdlog::info (" Before filtering set size: {}" , systemPathVariableSet.size ());
45
+
46
+ std::set<std::string> systemPathVariableFilteredSet;
47
+
48
+ spdlog::info (" Applying length distance heuristic based on a maximum difference in length of {}" , settings.getLengthConditionHeuristic ());
49
+ if (settings.getLengthConditionHeuristicEnabled ()) {
50
+
51
+ std::copy_if (
52
+ systemPathVariableSet.begin (),
53
+ systemPathVariableSet.end (),
54
+ std::inserter (systemPathVariableFilteredSet, systemPathVariableFilteredSet.end ()),
55
+ [inputCommand, settings](const std::string& value){
56
+
57
+ int absoluteLengthLetterDifference = std::abs (static_cast <int >(value.length ()) - static_cast <int >(inputCommand.length ()));
58
+
59
+ // This heuristic is used to improve runtimes by reducing the numbers of binaries to check based on the total amount of
60
+ // length differencies between the two words. By default, if their length is different by two or more letters, their
61
+ // distance do not get calculated
62
+ bool lengthCondition = absoluteLengthLetterDifference <= settings.getLengthConditionHeuristic ();
63
+
64
+ if (!lengthCondition)
65
+ return lengthCondition;
66
+
67
+ std::unordered_set<char > inputCommandCharSet = CommonUtils::getSetOfUniqueCharFromString (inputCommand);
68
+ std::unordered_set<char > currentBinaryCharSet = CommonUtils::getSetOfUniqueCharFromString (value);
69
+
70
+ std::unordered_set<char > intersectionSet;
71
+ for (char ch : inputCommandCharSet) {
72
+ if (currentBinaryCharSet.find (ch) != currentBinaryCharSet.end ())
73
+ intersectionSet.insert (ch);
74
+ }
75
+
76
+ bool letterCondition = intersectionSet.size () >= (inputCommandCharSet.size () / 2 );
77
+
78
+ return letterCondition;
79
+ }
80
+ );
81
+ } else
82
+ systemPathVariableFilteredSet = systemPathVariableSet;
83
+
84
+ if (settings.getLengthConditionHeuristicEnabled ()) {
85
+ spdlog::info (" After filtering set size: {}" , systemPathVariableFilteredSet.size ());
86
+
87
+ spdlog::info (" Printing content of system path set after filtering" );
88
+ // If verbose mode enabled print the newly filtered set
89
+ if (vm.count (" v" ))
90
+ CommonUtils::printSet (systemPathVariableFilteredSet);
91
+ }
92
+
93
+ spdlog::info (" Calculating distance Map" );
94
+ std::map<std::string, int > distanceMap = WordDistanceHandler::calculateWordDistance (inputCommand, systemPathVariableFilteredSet);
95
+
96
+ if (distanceMap.size () == 0 ) {
97
+ std::cout<<" Could not find any similar commands to \" " <<inputCommand<<" \"\n " ;
98
+ return false ;
99
+ }
100
+
101
+ int minValueInMap = INT_MAX;
102
+ for (auto const &entry : distanceMap) {
103
+ if (entry.second < minValueInMap)
104
+ minValueInMap = entry.second ;
105
+ }
106
+
107
+ std::vector<std::string> similarCommands;
108
+ for (auto const &entry : distanceMap) {
109
+ if (entry.second == minValueInMap) {
110
+ similarCommands.push_back (entry.first );
111
+ }
112
+ }
113
+
114
+ if (similarCommands.size () > 1 ) {
115
+ std::cout<<" Could not find command " + inputCommand + " . Were you looking for these?\n " ;
116
+ for (auto const &entry : similarCommands)
117
+ std::cout<<" - " <<entry<<" \n " ;
118
+ } else
119
+ std::cout<<" Could not find command " + inputCommand + " . Were you looking for \" " + similarCommands[0 ]<<" \" ?\n " ;
120
+
121
+ return true ;
122
+ }
123
+
124
+ /* *
125
+ * Ensures that the `command_not_found_handle` function is present in the `.bashrc` file by running the initializer script.
126
+ *
127
+ * @return int Returns 0 if the script executes successfully, otherwise returns a non-zero value on failure.
128
+ */
129
+ int ensureCommandNotFoundHandler () {
130
+ int result = system (" bash initializer/initialzer.sh" );
131
+
132
+ if (result == 0 )
133
+ spdlog::info (" Initializer script successfully executed." );
134
+ else
135
+ spdlog::error (" Error executing the initializer script. Return code: {}" , result);
136
+
137
+ return result;
138
+ }
139
+
140
+
13
141
int main (int argc, char * argv[]) {
14
142
15
143
std::string inputCommand;
144
+
145
+ po::variables_map vm;
146
+ po::options_description desc (" Allowed options" );
16
147
17
148
try {
18
-
19
149
// Handling program parameters
20
- po::options_description desc (" Allowed options" );
21
150
desc.add_options ()
22
151
(" i" , po::value<std::string>(), " The input command" )
23
152
(" e" , " Edit the configuration file" )
153
+ (" v" , " Verbose mode" )
24
154
(" help" , " Produce a help message" );
25
155
26
- po::variables_map vm;
27
156
po::store (po::parse_command_line (argc, argv, desc), vm);
28
157
po::notify (vm);
29
158
30
159
160
+ if (!vm.count (" v" )) {
161
+ spdlog::set_level (spdlog::level::off);
162
+ }
31
163
32
164
if (vm.count (" i" )) {
33
165
inputCommand = vm[" i" ].as <std::string>();
@@ -44,8 +176,6 @@ int main(int argc, char* argv[]) {
44
176
return 0 ;
45
177
}
46
178
47
-
48
-
49
179
}
50
180
catch (std::exception & e) {
51
181
std::cerr<<" error: " <<e.what ()<<" \n " ;
@@ -57,100 +187,10 @@ int main(int argc, char* argv[]) {
57
187
}
58
188
59
189
Settings settings;
60
- spdlog::info (" Settings successufully loaded." );
61
-
62
-
63
- // Writing command_not_found_handle funtion in .bashrc file if not present
64
- int result = system (" bash initializer/initialzer.sh" );
65
- if (result != 0 )
66
- spdlog::error (" Error executing the initializer script. Return code: {}" , result);
67
- else
68
- spdlog::info (" Initializer script successfully executed." );
69
-
70
- spdlog::info (" Printing content of system path vector" );
71
- CommonUtils::printVector (settings.getSystemPathVariablePaths ());
72
-
73
- // TODO: write a new program to update the database with each new binaries in the system each time a new bash shell is open
74
- // to reduce calcultion time
75
-
76
-
77
-
78
- std::set<std::string> systemPathVariableSet;
79
- for (const auto &entry : settings.getSystemPathVariablePaths ()) {
80
- std::cout<<" Content of: " <<entry<<" \n " ;
81
-
82
- std::vector<std::string> filesInPath = CommonUtils::getListOfFilesInPath (entry, false , true );
83
-
84
- systemPathVariableSet.insert (filesInPath.begin (), filesInPath.end ());
85
- }
86
-
87
- // TODO: use an heuristic to reduce calculation time further
88
- spdlog::info (" Printing content of system path set" );
89
- CommonUtils::printSet (systemPathVariableSet);
90
-
91
- spdlog::info (" Before filtering set size: {}" , systemPathVariableSet.size ());
92
-
93
- std::set<std::string> systemPathVariableFilteredSet;
94
-
95
-
96
- std::copy_if (
97
- systemPathVariableSet.begin (),
98
- systemPathVariableSet.end (),
99
- std::inserter (systemPathVariableFilteredSet, systemPathVariableFilteredSet.end ()),
100
- [inputCommand](const std::string& value){
101
-
102
- bool lengthCondition = std::abs (static_cast <int >(value.length ()) - static_cast <int >(inputCommand.length ())) <= 2 ;
103
-
104
- if (!lengthCondition)
105
- return lengthCondition;
106
-
107
- std::unordered_set<char > inputCommandCharSet = CommonUtils::getSetOfUniqueCharFromString (inputCommand);
108
- std::unordered_set<char > currentBinaryCharSet = CommonUtils::getSetOfUniqueCharFromString (value);
109
-
110
- std::unordered_set<char > intersectionSet;
111
- for (char ch : inputCommandCharSet) {
112
- if (currentBinaryCharSet.find (ch) != currentBinaryCharSet.end ()) {
113
- intersectionSet.insert (ch);
114
- }
115
- }
116
-
117
- bool letterCondition = intersectionSet.size () >= (inputCommandCharSet.size () / 2 );
118
-
119
- return letterCondition;
120
- }
121
- );
122
-
123
- spdlog::info (" After filtering set size: {}" , systemPathVariableFilteredSet.size ());
124
-
125
- spdlog::info (" Printing content of system path set after filtering" );
126
- CommonUtils::printSet (systemPathVariableFilteredSet);
127
-
128
- spdlog::info (" Calculating distance Map" );
129
- std::map<std::string, int > distanceMap = WordDistanceHandler::calculateWordDistance (inputCommand, systemPathVariableFilteredSet);
130
-
131
- int minValueInMap = INT_MAX;
132
- for (auto const &entry : distanceMap) {
133
- if (entry.second < minValueInMap)
134
- minValueInMap = entry.second ;
135
- }
136
-
137
- std::vector<std::string> similarCommands;
138
- for (auto const &entry : distanceMap) {
139
- if (entry.second == minValueInMap) {
140
- similarCommands.push_back (entry.first );
141
- }
142
- }
143
-
144
- std::cout<<" Could not find command " + inputCommand + " . Were you looking for" ;
145
- for (auto const &entry : similarCommands) {
146
- std::cout<<" \" " <<entry<<" \" " ;
147
- }
148
- std::cout<<" ?\n " ;
149
190
191
+ ensureCommandNotFoundHandler ();
150
192
193
+ suggestCommands (vm, inputCommand, settings);
151
194
152
- // spdlog::info("Printing distance Map");
153
- // WordDistanceHandler::printDistanceMap(distanceMap);
154
-
155
195
return 0 ;
156
196
}
0 commit comments