kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

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 }