Skip to content

Add bulk region hierarchy command to CLI#2540

Open
agessaman wants to merge 2 commits into
meshcore-dev:devfrom
agessaman:feat/regions-quick-loasd
Open

Add bulk region hierarchy command to CLI#2540
agessaman wants to merge 2 commits into
meshcore-dev:devfrom
agessaman:feat/regions-quick-loasd

Conversation

@agessaman
Copy link
Copy Markdown
Contributor

Add a new command region bulk for defining region hierarchies in a single line. This command allows users to create multiple regions in a single message. Updated the documentation to include usage examples and detailed parameter descriptions.

The primary use-case here is improving the regions configuration process by requiring fewer command messages to load a full set of regions on a repeater. This has the additional benefit that regions can be configured or reconfigured at multiple hops with more reliability—with region load or region put a dropped message can frustrate or break the configuration process.

Add a new command `region bulk` for defining region hierarchies in a single line. This command allows users to create multiple regions in a single message. Updated the documentation to include usage examples and detailed parameter descriptions.
@AI7NC
Copy link
Copy Markdown
Contributor

AI7NC commented May 12, 2026

This idea has my full support. This will allow much simpler regional loads for repeater operators by condensing in my region 8 load commands into a single command.

@towerviewcams
Copy link
Copy Markdown

8 load commands with many repeaters that I host will create allot of traffic and retry attempts. Anything that can be done to reduce and make this process more efficient should be considered.

@ripplebiz
Copy link
Copy Markdown
Member

I quite like this. A nifty shorthand.
I think 'region def ...' would prob read better than 'bulk'. Plus you get an extra byte! :-)

@agessaman agessaman marked this pull request as ready for review May 16, 2026 20:16
@agessaman
Copy link
Copy Markdown
Contributor Author

Updated to use region def .... Thanks for the feedback. :)

Comment thread src/helpers/CommonCLI.cpp
void CommonCLI::handleRegionCmd(char* command, char* reply) {
reply[0] = 0;

// `region def ...` — cursor-walk over space-separated tokens (must run before
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can be a bit more efficient with the delimiters and spaces, isn't that the same as

// `region def ...` — cursor-walk over space-separated tokens (must run before
  // parseTextParts, which only keeps 4 segments and mutates the buffer).
  char* cmd = command;

  while (*cmd == ' ') {
    cmd++;
  }

  if (strncmp(cmd, "region def", 10) == 0 && (cmd[10] == ' ' || cmd[10] == '\0')) {
    char* payload = cmd + 10;

    while (*payload == ' ') {
      payload++;
    }

    if (*payload == '\0') {
      snprintf(reply, 160, "Err - empty def");
      return;
    }

    RegionEntry* cursor = &_region_map->getWildcard();

    char* p = payload;

    // Trim trailing whitespace in-place; lets us use end-pointer arithmetic once.
    char* pend = p + strlen(p);
    while (pend > p && pend[-1] == ' ') *--pend = '\0';

    // Helper: advance past leading spaces (no allocation, pure pointer arithmetic).
    auto ltrim = [](char* s) -> char* {
      while (*s == ' ') s++;
      return s;
    };

    while (*p) {
      // Skip leading spaces and detect end.
      p = ltrim(p);
      if (*p == '\0') break;

      // Delimit the next space-separated token in-place.
      char* tok = p;
      while (*p && *p != ' ') p++;
      if (*p) *p++ = '\0';

      // Split token on '|' or ',' into name[|jump] — single forward scan.
      char* jump = nullptr;
      for (char* q = tok; *q; q++) {
        if (*q == '|' || *q == ',') {
          *q = '\0';
          jump = ltrim(q + 1);
          // Trim trailing spaces from jump.
          char* je = jump + strlen(jump);
          while (je > jump && je[-1] == ' ') *--je = '\0';
          break;
        }
      }

      char* name = ltrim(tok);

      if (*name == '\0') {
        snprintf(reply, 160, "Err - empty name");
        return;
      }

      if (jump && *jump == '\0') {
        snprintf(reply, 160, "Err - empty jump");
        return;
      }

      auto r = _region_map->putRegion(name, cursor->id);
      if (r == NULL) {
        snprintf(reply, 160, "Err - put failed: %s", name);
        return;
      }

      r->flags = 0;
      cursor = r;

      if (jump) {
        auto j = _region_map->findByNamePrefix(jump);
        if (j == NULL) {
          snprintf(reply, 160, "Err - unknown jump: %s", jump);
          return;
        }
        cursor = j;
      }
    }

    _region_map->exportTo(reply, 160);
    return;
  }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this one too—all paths to the same goal. If @ripplebiz likes the style better, I'm happy to use it instead. I just would like to be able to set up regions with a single command string. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants