rules.cc (5977B)
1 #include <kranewl/rules.hh> 2 #include <kranewl/env.hh> 3 4 #include <spdlog/spdlog.h> 5 6 #include <fstream> 7 8 std::vector<std::tuple<SearchSelector_ptr, Rules>> 9 Rules::compile_default_rules(std::string const& rules_path) 10 { 11 std::vector<std::tuple<SearchSelector_ptr, Rules>> 12 default_rules = {}; 13 14 if (!file_exists(rules_path)) 15 return default_rules; 16 17 std::ifstream rules_if(rules_path); 18 if (!rules_if.good()) 19 return default_rules; 20 21 std::string line; 22 23 while (std::getline(rules_if, line)) { 24 std::string::size_type pos = line.find('#'); 25 26 if (pos != std::string::npos) 27 line = line.substr(0, pos); 28 29 if (line.length() < 5) 30 continue; 31 32 line.erase(4, line.find_first_not_of(" \t\n\r\f\v")); 33 line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1); 34 35 if (line.length() < 5) 36 continue; 37 38 pos = line.find(':'); 39 std::string rules = line.substr(0, pos); 40 if (pos == std::string::npos || rules.empty() || pos >= (line.size() - 1)) 41 continue; 42 43 line = line.substr(pos + 1); 44 if (line.length() < 5) 45 continue; 46 47 SearchSelector::SelectionCriterium criterium; 48 switch (line[1]) { 49 case 'T': 50 { 51 switch (line[0]) { 52 case '=': criterium = SearchSelector::SelectionCriterium::ByTitleEquals; break; 53 case '~': criterium = SearchSelector::SelectionCriterium::ByTitleContains; break; 54 default: continue; 55 } 56 57 break; 58 } 59 case 'A': 60 { 61 switch (line[0]) { 62 case '=': criterium = SearchSelector::SelectionCriterium::ByAppIdEquals; break; 63 case '~': criterium = SearchSelector::SelectionCriterium::ByAppIdContains; break; 64 default: continue; 65 } 66 67 break; 68 } 69 case 'H': 70 { 71 switch (line[0]) { 72 case '=': criterium = SearchSelector::SelectionCriterium::ByHandleEquals; break; 73 case '~': criterium = SearchSelector::SelectionCriterium::ByHandleContains; break; 74 default: continue; 75 } 76 77 break; 78 } 79 default: continue; 80 } 81 82 default_rules.push_back({ 83 new SearchSelector{criterium, line.substr(3)}, 84 Rules::parse_rules(rules, true) 85 }); 86 } 87 88 return default_rules; 89 } 90 91 Rules 92 Rules::parse_rules(std::string_view rule, bool ignore_prefix) 93 { 94 static const std::string prefix = "kranewl:"; 95 static auto snapedge_list_handler = [](Rules& rules, auto iter) { 96 switch (*iter) { 97 case 'l': *rules.snap_edges |= WLR_EDGE_LEFT; return; 98 case 't': *rules.snap_edges |= WLR_EDGE_TOP; return; 99 case 'r': *rules.snap_edges |= WLR_EDGE_RIGHT; return; 100 case 'b': *rules.snap_edges |= WLR_EDGE_BOTTOM; return; 101 default: return; 102 } 103 }; 104 105 Rules rules{}; 106 std::string_view::const_iterator iter; 107 108 if (!ignore_prefix) { 109 std::string::size_type prefix_pos = rule.find(prefix); 110 if (prefix_pos == std::string::npos) 111 return rules; 112 113 iter = rule.begin() + prefix_pos + prefix.size(); 114 } else 115 iter = rule.begin(); 116 117 spdlog::info("Parsing rule: {}", std::string(iter, rule.end())); 118 119 bool invert = false; 120 bool next_output = false; 121 bool next_context = false; 122 bool next_workspace = false; 123 124 std::optional<decltype(snapedge_list_handler)> 125 list_handler = std::nullopt; 126 127 for (; iter != rule.end(); ++iter) { 128 if (*iter == '.') { 129 list_handler = std::nullopt; 130 continue; 131 } 132 if (list_handler) { 133 (*list_handler)(rules, iter); 134 continue; 135 } 136 137 switch (*iter) { 138 case ':': return rules; 139 case '!': invert = true; continue; 140 case 'O': next_output = true; continue; 141 case 'C': next_context = true; continue; 142 case 'W': next_workspace = true; continue; 143 case '@': rules.do_focus = !invert; break; 144 case 'f': rules.do_float = !invert; break; 145 case 'F': rules.do_fullscreen = !invert; break; 146 case 'c': rules.do_center = !invert; break; 147 case '0': // fallthrough 148 case '1': // fallthrough 149 case '2': // fallthrough 150 case '3': // fallthrough 151 case '4': // fallthrough 152 case '5': // fallthrough 153 case '6': // fallthrough 154 case '7': // fallthrough 155 case '8': // fallthrough 156 case '9': 157 { 158 if (next_output) 159 rules.to_output = *iter - '0'; 160 if (next_context) 161 rules.to_context = *iter - '0'; 162 if (next_workspace) 163 rules.to_workspace = *iter - '0'; 164 break; 165 } 166 case 'S': 167 { 168 if (!rules.snap_edges) 169 *rules.snap_edges = WLR_EDGE_NONE; 170 171 list_handler = snapedge_list_handler; 172 break; 173 } 174 default: break; 175 } 176 177 invert = false; 178 next_output = false; 179 next_context = false; 180 next_workspace = false; 181 } 182 183 return rules; 184 } 185 186 187 Rules 188 Rules::merge_rules(Rules const& base, Rules const& merger) 189 { 190 Rules rules = base; 191 192 if (merger.do_focus) 193 rules.do_focus = merger.do_focus; 194 if (merger.do_float) 195 rules.do_float = merger.do_float; 196 if (merger.do_center) 197 rules.do_center = merger.do_center; 198 if (merger.do_fullscreen) 199 rules.do_fullscreen = merger.do_fullscreen; 200 if (merger.to_output) 201 rules.to_output = merger.to_output; 202 if (merger.to_context) 203 rules.to_context = merger.to_context; 204 if (merger.to_workspace) 205 rules.to_workspace = merger.to_workspace; 206 if (merger.snap_edges) 207 rules.snap_edges = merger.snap_edges; 208 209 return rules; 210 }