Repository: dankamongmen/notcurses (language: python)

Issue:
logs don't effect a carriage return on windows
some accursed CRLF garbage.

![2021-12-19-031725_2634x1417_scrot](https://user-images.githubusercontent.com/143473/146668303-a1500a2f-16d4-4883-88c6-2e2f6b42b028.png)

logs don't effect a carriage return on windows
some accursed CRLF garbage.

![2021-12-19-031725_2634x1417_scrot](https://user-images.githubusercontent.com/143473/146668303-a1500a2f-16d4-4883-88c6-2e2f6b42b028.png)



Discussion / hints:
note that redirecting stderr leaves a file that looks fine
`dankamongmen/logging-crnl` branch
note that redirecting stderr leaves a file that looks fine
`dankamongmen/logging-crnl` branch

Fix patch:
diff --git a/src/lib/automaton.c b/src/lib/automaton.c
index 5ca00ec10..51546e10b 100644
--- a/src/lib/automaton.c
+++ b/src/lib/automaton.c
@@ -92,7 +92,7 @@ void input_free_esctrie(automaton* a){
 static int
 esctrie_make_kleene(automaton* a, esctrie* e, unsigned follow, esctrie* term){
   if(e->ntype != NODE_SPECIAL){
-    logerror("can't make node type %d string\n", e->ntype);
+    logerror("can't make node type %d string", e->ntype);
     return -1;
   }
   for(unsigned i = 0 ; i < 0x80 ; ++i){
@@ -108,11 +108,11 @@ esctrie_make_kleene(automaton* a, esctrie* e, unsigned follow, esctrie* term){
 static int
 esctrie_make_function(esctrie* e, triefunc fxn){
   if(e->ntype != NODE_SPECIAL){
-    logerror("can't make node type %d function\n", e->ntype);
+    logerror("can't make node type %d function", e->ntype);
     return -1;
   }
   if(e->trie){
-    logerror("can't make followed function\n");
+    logerror("can't make followed function");
     return -1;
   }
   e->ntype = NODE_FUNCTION;
@@ -123,11 +123,11 @@ esctrie_make_function(esctrie* e, triefunc fxn){
 static esctrie*
 esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
   if(e->ntype == NODE_STRING){
-    logerror("repeated string node\n");
+    logerror("repeated string node");
     return NULL;
   }
   if(e->ntype != NODE_SPECIAL){
-    logerror("can't make node type %d string\n", e->ntype);
+    logerror("can't make node type %d string", e->ntype);
     return NULL;
   }
   for(int i = 0 ; i < 0x80 ; ++i){
@@ -135,7 +135,7 @@ esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
       continue;
     }
     if(e->trie[i]){
-      logerror("can't make %c-followed string\n", i);
+      logerror("can't make %c-followed string", i);
       return NULL;
     }
   }
@@ -178,7 +178,7 @@ esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
     term->ntype = NODE_SPECIAL;
     e = term;
   }
-  logdebug("made string: %u\n", esctrie_idx(a, e));
+  logdebug("made string: %u", esctrie_idx(a, e));
   return e;
 }
 
@@ -207,7 +207,7 @@ link_kleene(automaton* a, esctrie* e, unsigned follow){
   for(unsigned int i = 0 ; i < 0x80 ; ++i){
     if(i == follow){
       if(e->trie[i]){
-        logerror("drain terminator already registered\n");
+        logerror("drain terminator already registered");
         return NULL;
       }
       e->trie[follow] = esctrie_idx(a, term);
@@ -229,7 +229,7 @@ get_phi_node(automaton* a, esctrie* e){
   for(int i = '0' ; i <= '9' ; ++i){
     if( (targ = esctrie_from_idx(a, e->trie[i])) ){
       if(targ->ntype == NODE_NUMERIC){
-        logtrace("found existing phi node %u[%c]->%u\n", esctrie_idx(a, e), i, esctrie_idx(a, targ));
+        logtrace("found existing phi node %u[%c]->%u", esctrie_idx(a, e), i, esctrie_idx(a, targ));
         break;
       }else{
         ++nonphis;
@@ -241,7 +241,7 @@ get_phi_node(automaton* a, esctrie* e){
   // one, be sure to mark it numeric, and add all digit links back to itself.
   if(targ == NULL){
     if(nonphis == 10){
-      logerror("ten non-phi links from %u\n", esctrie_idx(a, e));
+      logerror("ten non-phi links from %u", esctrie_idx(a, e));
       return 0;
     }
     if((targ = esctrie_from_idx(a, create_esctrie_node(a, 0))) == 0){
@@ -278,19 +278,19 @@ get_eta_node(automaton* a, esctrie* phi, unsigned successor){
 static inline void
 add_phi_and_eta_chain(const automaton *a, esctrie* e, unsigned phi,
                       unsigned follow, unsigned eta){
-//logtrace("working with %u phi: %u follow: %u eta: %u\n", esctrie_idx(a, e), phi, follow, eta);
+//logtrace("working with %u phi: %u follow: %u eta: %u", esctrie_idx(a, e), phi, follow, eta);
   for(int i = '0' ; i <= '9' ; ++i){
     esctrie* chain = esctrie_from_idx(a, e->trie[i]);
     if(chain == NULL){
-      //logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, phi);
+      //logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, phi);
       e->trie[i] = phi;
     }else if(chain->ntype == NODE_SPECIAL){
-//logdebug("propagating along %u[%c]\n", e->trie[i], i);
+//logdebug("propagating along %u[%c]", e->trie[i], i);
       add_phi_and_eta_chain(a, esctrie_from_idx(a, e->trie[i]), phi, follow, eta);
     }
   }
   if(e->trie[follow] == 0){
-    //logdebug("linking %u[%u] to %u\n", esctrie_idx(a, e), follow, eta);
+    //logdebug("linking %u[%u] to %u", esctrie_idx(a, e), follow, eta);
     e->trie[follow] = eta;
   }
 }
@@ -304,7 +304,7 @@ static inline void
 add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
                         int pfxlen, esctrie* phi, unsigned follow,
                         esctrie* eta, unsigned inphi){
-//logtrace("working with %u %d prefix [%*.*s]\n", esctrie_idx(a, e), pfxlen, pfxlen, pfxlen, prefix);
+//logtrace("working with %u %d prefix [%*.*s]", esctrie_idx(a, e), pfxlen, pfxlen, pfxlen, prefix);
   // if pfxlen == 0, we found a match for our fixed prefix. start adding phi
   // links whereever we can. where we find chained numerics, add an eta link.
   if(pfxlen == 0){
@@ -316,14 +316,14 @@ add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
     ++prefix;
     --pfxlen;
     if(*prefix != 'N'){
-      logerror("illegal wildcard in prefix %c\n", *prefix);
+      logerror("illegal wildcard in prefix %c", *prefix);
       return;
     }
     ++prefix;
     --pfxlen;
     for(int i = '0' ; i <= '9' ; ++i){
       if(e->trie[i] == 0){
-        //logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, esctrie_idx(a, phi));
+        //logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, esctrie_idx(a, phi));
         e->trie[i] = esctrie_idx(a, phi);
       }else{
         add_phi_and_eta_recurse(a, esctrie_from_idx(a, e->trie[i]),
@@ -334,7 +334,7 @@ add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
     if(inphi){
       for(int i = '0' ; i <= '9' ; ++i){
         if(e->trie[i] == 0){
-          //logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, esctrie_idx(a, phi));
+          //logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, esctrie_idx(a, phi));
           e->trie[i] = esctrie_idx(a, phi);
         }else if(e->trie[i] != esctrie_idx(a, e)){
           add_phi_and_eta_recurse(a, esctrie_from_idx(a, e->trie[i]),
@@ -377,7 +377,7 @@ add_phi_and_eta(automaton* a, const char* prefix, size_t pfxlen,
 static esctrie*
 link_numeric(automaton* a, const char* prefix, int pfxlen,
              esctrie* e, unsigned char follow){
-  logdebug("adding numeric with follow %c following %*.*s\n", follow, pfxlen, pfxlen, prefix);
+  logdebug("adding numeric with follow %c following %*.*s", follow, pfxlen, pfxlen, prefix);
   unsigned phiidx = get_phi_node(a, e);
   if(phiidx == 0){
     return NULL;
@@ -390,8 +390,8 @@ link_numeric(automaton* a, const char* prefix, int pfxlen,
   }
   phi = esctrie_from_idx(a, phiidx);
   esctrie* eta = esctrie_from_idx(a, etaidx);
-  logtrace("phi node: %u->%u\n", esctrie_idx(a, e), esctrie_idx(a, phi));
-  logtrace("eta node: %u philink[%c]: %u\n", esctrie_idx(a, eta), follow, phi->trie[follow]);
+  logtrace("phi node: %u->%u", esctrie_idx(a, e), esctrie_idx(a, phi));
+  logtrace("eta node: %u philink[%c]: %u", esctrie_idx(a, eta), follow, phi->trie[follow]);
   // eta is now bound to phi, and phi links something at all digits, but no
   // other links are guaranteed. walk the automaton, finding all possible
   // prefixes of φ (and linking to φ) and all possible prefixes of ή (and
@@ -414,7 +414,7 @@ insert_path(automaton* a, const char* seq){
   while( (c = *seq++) ){
     if(c == '\\'){
       if(inescape){
-        logerror("illegal escape: \\\n");
+        logerror("illegal escape: \\");
         return NULL;
       }
       inescape = true;
@@ -422,7 +422,7 @@ insert_path(automaton* a, const char* seq){
       if(c == 'N'){
         // a numeric must be followed by some terminator
         if(!*seq){
-          logerror("illegal numeric terminator\n");
+          logerror("illegal numeric terminator");
           return NULL;
         }
         c = *seq++;
@@ -439,7 +439,7 @@ insert_path(automaton* a, const char* seq){
       }else if(c == 'D'){ // drain (kleene closure)
         // a kleene must be followed by some terminator
         if(!*seq){
-          logerror("illegal kleene terminator\n");
+          logerror("illegal kleene terminator");
           return NULL;
         }
         c = *seq++;
@@ -448,7 +448,7 @@ insert_path(automaton* a, const char* seq){
           return NULL;
         }
       }else{
-        logerror("illegal escape: %u\n", c);
+        logerror("illegal escape: %u", c);
         return NULL;
       }
       inescape = false;
@@ -478,11 +478,11 @@ insert_path(automaton* a, const char* seq){
       }
       eptr = esctrie_from_idx(a, eidx);
       eptr = esctrie_from_idx(a, eptr->trie[c]);
-      logtrace("added fixed %c %u as %u\n", c, c, esctrie_idx(a, eptr));
+      logtrace("added fixed %c %u as %u", c, c, esctrie_idx(a, eptr));
     }
   }
   if(inescape){
-    logerror("illegal escape at end of line\n");
+    logerror("illegal escape at end of line");
     return NULL;
   }
   return eptr;
@@ -503,7 +503,7 @@ int inputctx_add_cflow(automaton* a, const char* seq, triefunc fxn){
 int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
                               unsigned shift, unsigned ctrl, unsigned alt){
   if(esc[0] != NCKEY_ESC || strlen(esc) < 2){ // assume ESC prefix + content
-    logerror("not an escape (0x%x)\n", special);
+    logerror("not an escape (0x%x)", special);
     return -1;
   }
   esctrie* eptr = insert_path(a, esc + 1);
@@ -514,7 +514,7 @@ int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
   // an example, see "kend" and "kc1" in st ("simple term" from suckless) :/.
   if(eptr->ni.id){ // already had one here!
     if(eptr->ni.id != special){
-      logwarn("already added escape (got 0x%x, wanted 0x%x)\n", eptr->ni.id, special);
+      logwarn("already added escape (got 0x%x, wanted 0x%x)", eptr->ni.id, special);
     }
   }else{
     eptr->ni.id = special;
@@ -523,7 +523,7 @@ int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
     eptr->ni.alt = alt;
     eptr->ni.y = 0;
     eptr->ni.x = 0;
-    logdebug("added 0x%08x to %u\n", special, esctrie_idx(a, eptr));
+    logdebug("added 0x%08x to %u", special, esctrie_idx(a, eptr));
   }
   return 0;
 }
@@ -535,7 +535,7 @@ int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
 int walk_automaton(automaton* a, struct inputctx* ictx, unsigned candidate,
                    ncinput* ni){
   if(candidate >= 0x80){
-    logerror("eight-bit char %u in control sequence\n", candidate);
+    logerror("eight-bit char %u in control sequence", candidate);
     return -1;
   }
   esctrie* e = esctrie_from_idx(a, a->state);
@@ -566,7 +566,7 @@ int walk_automaton(automaton* a, struct inputctx* ictx, unsigned candidate,
       ni->alt = true;
       return 1;
     }
-    loginfo("unexpected transition on %u[%u]\n",
+    loginfo("unexpected transition on %u[%u]",
             esctrie_idx(a, e), candidate);
     return -1;
   }
diff --git a/src/lib/blit.c b/src/lib/blit.c
index 91effcf6e..24e019e9f 100644
--- a/src/lib/blit.c
+++ b/src/lib/blit.c
@@ -997,11 +997,11 @@ const char* notcurses_str_blitter(ncblitter_e blitfxn){
 
 int ncblit_bgrx(const void* data, int linesize, const struct ncvisual_options* vopts){
   if(vopts->leny <= 0 || vopts->lenx <= 0){
-    logerror("invalid lengths %u %u\n", vopts->leny, vopts->lenx);
+    logerror("invalid lengths %u %u", vopts->leny, vopts->lenx);
     return -1;
   }
   if(vopts->n == NULL){
-    logerror("prohibited null plane\n");
+    logerror("prohibited null plane");
     return -1;
   }
   void* rdata = bgra_to_rgba(data, vopts->leny, &linesize, vopts->lenx, 0xff);
@@ -1043,11 +1043,11 @@ int ncblit_rgb_packed(const void* data, int linesize,
 
 int ncblit_rgba(const void* data, int linesize, const struct ncvisual_options* vopts){
   if(vopts->leny <= 0 || vopts->lenx <= 0){
-    logerror("invalid lengths %u %u\n", vopts->leny, vopts->lenx);
+    logerror("invalid lengths %u %u", vopts->leny, vopts->lenx);
     return -1;
   }
   if(vopts->n == NULL){
-    logerror("prohibited null plane\n");
+    logerror("prohibited null plane");
     return -1;
   }
   struct ncvisual* ncv = ncvisual_from_rgba(data, vopts->leny, linesize, vopts->lenx);
diff --git a/src/lib/egcpool.h b/src/lib/egcpool.h
index 005d08e65..4366c2e60 100644
--- a/src/lib/egcpool.h
+++ b/src/lib/egcpool.h
@@ -104,7 +104,7 @@ utf8_egc_len(const char* gcluster, int* colcount){
     r = mbrtowc(&wc, gcluster, MB_LEN_MAX, &mbt);
     if(r < 0){
       // FIXME probably ought escape this somehow
-      logerror("invalid UTF8: %s\n", gcluster);
+      logerror("invalid UTF8: %s", gcluster);
       return -1;
     }
     if(prevw && !injoin && uc_is_grapheme_break(prevw, wc)){
@@ -127,7 +127,7 @@ utf8_egc_len(const char* gcluster, int* colcount){
         }
         cols = 1;
         if(iswcntrl(wc)){
-          logerror("prohibited or invalid unicode: 0x%08x\n", (unsigned)wc);
+          logerror("prohibited or invalid unicode: 0x%08x", (unsigned)wc);
           return -1;
         }
       }
@@ -241,32 +241,6 @@ egcpool_stash(egcpool* pool, const char* egc, size_t ulen){
   return -1; // should never get here
 }
 
-// Run a consistency check on the offset; ensure it's a valid, non-empty EGC.
-static inline bool
-egcpool_check_validity(const egcpool* pool, int offset){
-  if(offset >= pool->poolsize){
-    fprintf(stderr, "offset 0x%06x greater than size (%d)\n", offset, pool->poolsize);
-    return false;
-  }
-  const char* egc = pool->pool + offset;
-  if(*egc == '\0'){
-    fprintf(stderr, "bad offset 0x%06x: empty\n", offset);
-    return false;
-  }
-  mbstate_t mbstate;
-  memset(&mbstate, 0, sizeof(mbstate));
-  do{
-    wchar_t wcs;
-    int r = mbrtowc(&wcs, egc, strlen(egc), &mbstate);
-    if(r < 0){
-      fprintf(stderr, "invalid utf8 at offset 0x%06x [%s]\n", offset, strerror(errno));
-      return false;
-    }
-    egc += r;
-  }while(*egc);
-  return true;
-}
-
 // remove the egc from the pool. start at offset, and zero out everything until
 // we find a zero (our own NUL terminator). remove that number of bytes from
 // the usedcount.
diff --git a/src/lib/fbuf.h b/src/lib/fbuf.h
index f9df675e4..1e80f4533 100644
--- a/src/lib/fbuf.h
+++ b/src/lib/fbuf.h
@@ -229,11 +229,11 @@ fbuf_emit(fbuf* f, const char* esc){
 static inline void
 fbuf_free(fbuf* f){
   if(f){
-//    logdebug("Releasing from %" PRIu32 "B (%" PRIu32 "B)\n", f->size, f->used);
+//    logdebug("Releasing from %" PRIu32 "B (%" PRIu32 "B)", f->size, f->used);
     if(f->buf){
 #if __linux__
       if(munmap(f->buf, f->size)){
-        //logwarn("Error unmapping alloc (%s)\n", strerror(errno));
+        //logwarn("Error unmapping alloc (%s)", strerror(errno));
       }
 #else
       free(f->buf);
@@ -255,7 +255,7 @@ blocking_write(int fd, const char* buf, size_t buflen){
     ssize_t w = write(fd, buf + written, buflen - written);
     if(w < 0){
       if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR && errno != EBUSY){
-        logerror("Error writing out data on %d (%s)\n", fd, strerror(errno));
+        logerror("Error writing out data on %d (%s)", fd, strerror(errno));
         return -1;
       }
     }else{
diff --git a/src/lib/fd.c b/src/lib/fd.c
index 84f525fdb..068507eb8 100644
--- a/src/lib/fd.c
+++ b/src/lib/fd.c
@@ -94,7 +94,7 @@ ncfdplane_create_internal(ncplane* n, const ncfdplane_options* opts, int fd,
                           ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn,
                           bool thread){
   if(opts->flags > 0){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
   ncfdplane* ret = malloc(sizeof(*ret));
   if(ret == NULL){
@@ -194,7 +194,7 @@ launch_pipe_process(int* pipefd, int* pidfd, unsigned usepath,
   p = syscall(__NR_clone3, &clargs, sizeof(clargs));
   if(p == 0){ // child
     if(dup2(pipes[1], STDOUT_FILENO) < 0 || dup2(pipes[1], STDERR_FILENO) < 0){
-      logerror("Couldn't dup() %d (%s)\n", pipes[1], strerror(errno));
+      logerror("couldn't dup() %d (%s)", pipes[1], strerror(errno));
       exit(EXIT_FAILURE);
     }
     if(env){
@@ -206,13 +206,13 @@ launch_pipe_process(int* pipefd, int* pidfd, unsigned usepath,
     }
     exit(EXIT_FAILURE);
   }else if(p < 0){
-    logwarn("clone3() failed (%s), using posix_spawn()\n", strerror(errno));
+    logwarn("clone3() failed (%s), using posix_spawn()", strerror(errno));
   }
 #endif
   if(p < 0){
     posix_spawn_file_actions_t factions;
     if(posix_spawn_file_actions_init(&factions)){
-      logerror("couldn't initialize spawn file actions\n");
+      logerror("couldn't initialize spawn file actions");
       return -1;
     }
     posix_spawn_file_actions_adddup2(&factions, pipes[1], STDOUT_FILENO);
@@ -224,7 +224,7 @@ launch_pipe_process(int* pipefd, int* pidfd, unsigned usepath,
       r = posix_spawn(&p, bin, &factions, NULL, arg, env);
     }
     if(r){
-      logerror("posix_spawn %s failed (%s)\n", bin, strerror(errno));
+      logerror("posix_spawn %s failed (%s)", bin, strerror(errno));
     }
     posix_spawn_file_actions_destroy(&factions);
   }
@@ -347,7 +347,7 @@ ncexecvpe(ncplane* n, const ncsubproc_options* opts, unsigned usepath,
     return NULL;
   }
   if(opts->flags > 0){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
 #ifndef __MINGW32__
   int fd = -1;
@@ -407,7 +407,7 @@ int ncsubproc_destroy(ncsubproc* n){
 #ifndef __MINGW32__
 #ifdef USING_PIDFD
     if(n->pidfd >= 0){
-      loginfo("Sending SIGKILL to pidfd %d\n", n->pidfd);
+      loginfo("sending SIGKILL to pidfd %d", n->pidfd);
       if(syscall(__NR_pidfd_send_signal, n->pidfd, SIGKILL, NULL, 0)){
         kill(n->pid, SIGKILL);
       }
@@ -415,7 +415,7 @@ int ncsubproc_destroy(ncsubproc* n){
 #else
     pthread_mutex_lock(&n->lock);
     if(!n->waited){
-      loginfo("Sending SIGKILL to PID %d\n", n->pid);
+      loginfo("sending SIGKILL to PID %d", n->pid);
       kill(n->pid, SIGKILL);
     }
     pthread_mutex_unlock(&n->lock);
@@ -456,12 +456,12 @@ int get_tty_fd(FILE* ttyfp){
   int fd = -1;
   if(ttyfp){
     if((fd = fileno(ttyfp)) < 0){
-      logwarn("no file descriptor was available in outfp %p\n", ttyfp);
+      logwarn("no file descriptor was available in outfp %p", ttyfp);
     }else{
       if(tty_check(fd)){
         fd = dup(fd);
       }else{
-        loginfo("fd %d is not a TTY\n", fd);
+        loginfo("fd %d is not a TTY", fd);
         fd = -1;
       }
     }
@@ -469,17 +469,17 @@ int get_tty_fd(FILE* ttyfp){
   if(fd < 0){
     fd = open("/dev/tty", O_RDWR | O_CLOEXEC | O_NOCTTY);
     if(fd < 0){
-      loginfo("couldn't open /dev/tty (%s)\n", strerror(errno));
+      loginfo("couldn't open /dev/tty (%s)", strerror(errno));
     }else{
       if(!tty_check(fd)){
-        loginfo("file descriptor for /dev/tty (%d) is not actually a TTY\n", fd);
+        loginfo("file descriptor for /dev/tty (%d) is not actually a TTY", fd);
         close(fd);
         fd = -1;
       }
     }
   }
   if(fd >= 0){
-    loginfo("returning TTY fd %d\n", fd);
+    loginfo("returning TTY fd %d", fd);
   }
   return fd;
 }
diff --git a/src/lib/fill.c b/src/lib/fill.c
index e17c82873..d9a1b8e48 100644
--- a/src/lib/fill.c
+++ b/src/lib/fill.c
@@ -80,7 +80,7 @@ ncplane_polyfill_inner(ncplane* n, unsigned y, unsigned x, const nccell* c, cons
 int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
   if(ystart < 0){
     if(ystart != -1){
-      logerror("invalid y: %d\n", ystart);
+      logerror("invalid y: %d", ystart);
       return -1;
     }
     ystart = n->y;
@@ -88,14 +88,14 @@ int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
   unsigned y = ystart;
   if(xstart < 0){
     if(xstart != -1){
-      logerror("invalid x: %d\n", xstart);
+      logerror("invalid x: %d", xstart);
       return -1;
     }
     xstart = n->x;
   }
   unsigned x = xstart;
   if(y >= n->leny || x >= n->lenx){
-    logerror("invalid start: %u/%u (%u/%u)\n", y, x, n->leny, n->lenx);
+    logerror("invalid start: %u/%u (%u/%u)", y, x, n->leny, n->lenx);
     return -1;
   }
   const nccell* cur = &n->fb[nfbcellidx(n, y, x)];
@@ -122,19 +122,19 @@ check_gradient_channel_args(uint32_t ul, uint32_t ur, uint32_t bl, uint32_t br){
      ncchannel_default_p(bl) || ncchannel_default_p(br)){
     if(!(ncchannel_default_p(ul) && ncchannel_default_p(ur) &&
          ncchannel_default_p(bl) && ncchannel_default_p(br))){
-      logerror("some (not all) channels were defaults\n");
+      logerror("some (not all) channels were defaults");
       return true;
     }
   }
   if(ncchannel_alpha(ul) != ncchannel_alpha(ur) ||
      ncchannel_alpha(ur) != ncchannel_alpha(bl) ||
      ncchannel_alpha(bl) != ncchannel_alpha(br)){
-    logerror("channel alphas didn't match\n");
+    logerror("channel alphas didn't match");
     return true;
   }
   if(ncchannel_palindex_p(ul) || ncchannel_palindex_p(bl) ||
      ncchannel_palindex_p(br) || ncchannel_palindex_p(ur)){
-    logerror("can't blend palette-indexed color\n");
+    logerror("can't blend palette-indexed color");
     return true;
   }
   return false;
@@ -179,7 +179,7 @@ calc_highgradient(nccell* c, uint32_t ul, uint32_t ur, uint32_t ll,
 int ncplane_gradient2x1(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
                         uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr){
   if(!notcurses_canutf8(ncplane_notcurses(n))){
-    logerror("highdef gradients require utf8\n");
+    logerror("highdef gradients require utf8");
     return -1;
   }
   if(check_gradient_channel_args(ul, ur, ll, lr)){
@@ -191,7 +191,7 @@ int ncplane_gradient2x1(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
   }
   if(xlen == 1){
     if(ul != ur || ll != lr){
-      logerror("horizontal channel variation in single column\n");
+      logerror("horizontal channel variation in single column");
       return -1;
     }
   }
@@ -237,18 +237,18 @@ int ncplane_gradient(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
   if(ylen == 1){
     if(xlen == 1){
       if(ul != ur || ur != br || br != bl){
-        logerror("channel variation in 1x1 area\n");
+        logerror("channel variation in 1x1 area");
         return -1;
       }
     }else{
       if(ul != bl || ur != br){
-        logerror("vertical channel variation in single row\n");
+        logerror("vertical channel variation in single row");
         return -1;
       }
     }
   }else if(xlen == 1){
     if(ul != ur || bl != br){
-      logerror("horizontal channel variation in single column\n");
+      logerror("horizontal channel variation in single column");
       return -1;
     }
   }
@@ -327,7 +327,7 @@ rotate_channels(ncplane* src, const nccell* c, uint32_t* fchan, uint32_t* bchan)
     *bchan = *fchan;
     return 0;
   }
-  logerror("Invalid EGC for rotation [%s]\n", egc);
+  logerror("invalid EGC for rotation [%s]", egc);
   return -1;
 }
 
diff --git a/src/lib/gpm.c b/src/lib/gpm.c
index e01e3b965..f94a9856c 100644
--- a/src/lib/gpm.c
+++ b/src/lib/gpm.c
@@ -17,10 +17,10 @@ gpmwatcher(void* vti){
   const int space = sizeof(cmdbuf) - 3;
   while(true){
     if(!Gpm_GetEvent(&gev)){
-      logerror("error reading from gpm daemon\n");
+      logerror("error reading from gpm daemon");
       continue;
     }
-    loginfo("got gpm event y=%hd x=%hd mod=%u butt=%u\n", gev.y, gev.x,
+    loginfo("got gpm event y=%hd x=%hd mod=%u butt=%u", gev.y, gev.x,
             (unsigned)gev.modifiers, (unsigned)gev.buttons);
     if(gev.y < 0 || gev.x < 0){
       logwarn("negative input %hd %hd", gev.x, gev.y);
@@ -29,7 +29,7 @@ gpmwatcher(void* vti){
     // gpm is 0-indexed, but we assume mice reports to be 1-indexed, as they
     // are in the XTerm protocols. no need to account for margins here.
     if(snprintf(cmdbuf + 3, space, "%hd;%hd;%hdM", 0, gev.x + 1, gev.y + 1) >= space){
-      logwarn("input overflowed %hd %hd\n", gev.x, gev.y);
+      logwarn("input overflowed %hd %hd", gev.x, gev.y);
       continue;
     }
     ncinput_shovel(ti->ictx, cmdbuf, strlen(cmdbuf));
@@ -45,16 +45,16 @@ int gpm_connect(tinfo* ti){
   gpmconn.minMod = 0;
   gpmconn.maxMod = 0; // allow shift+drag to be used for direct copy+paste
   if(Gpm_Open(&gpmconn, 0) == -1){
-    logerror("couldn't connect to gpm\n");
+    logerror("couldn't connect to gpm");
     return -1;
   }
   if(pthread_create(&ti->gpmthread, NULL, gpmwatcher, ti)){
-    logerror("couldn't spawn gpm thread\n");
+    logerror("couldn't spawn gpm thread");
     Gpm_Close();
     memset(&gpmconn, 0, sizeof(gpmconn));
     return -1;
   }
-  loginfo("connected to gpm on %d\n", gpm_fd);
+  loginfo("connected to gpm on %d", gpm_fd);
   return gpm_fd;
 }
 
diff --git a/src/lib/in.c b/src/lib/in.c
index c2d804118..408eb5338 100644
--- a/src/lib/in.c
+++ b/src/lib/in.c
@@ -155,9 +155,9 @@ prep_xtmodkeys(inputctx* ictx){
                                  k->shift, k->ctrl, k->alt)){
       return -1;
     }
-    logdebug("added %u\n", k->key);
+    logdebug("added %u", k->key);
   }
-  loginfo("added all xtmodkeys\n");
+  loginfo("added all xtmodkeys");
   return 0;
 }
 
@@ -330,21 +330,21 @@ prep_special_keys(inputctx* ictx){
   for(k = keys ; k->tinfo ; ++k){
     char* seq = tigetstr(k->tinfo);
     if(seq == NULL || seq == (char*)-1){
-      loginfo("no terminfo declaration for %s\n", k->tinfo);
+      loginfo("no terminfo declaration for %s", k->tinfo);
       continue;
     }
     if(seq[0] != NCKEY_ESC || strlen(seq) < 2){ // assume ESC prefix + content
-      logwarn("invalid escape: %s (0x%x)\n", k->tinfo, k->key);
+      logwarn("invalid escape: %s (0x%x)", k->tinfo, k->key);
       continue;
     }
     if(inputctx_add_input_escape(&ictx->amata, seq, k->key, k->shift, k->ctrl, k->alt)){
       return -1;
     }
-    logdebug("support for terminfo's %s: %s\n", k->tinfo, seq);
+    logdebug("support for terminfo's %s: %s", k->tinfo, seq);
   }
   const char* bs = tigetstr("kbs");
   if(bs == NULL){
-    logwarn("no backspace key was defined\n");
+    logwarn("no backspace key was defined");
   }else{
     if(bs[0] == NCKEY_ESC){
       if(inputctx_add_input_escape(&ictx->amata, bs, NCKEY_BACKSPACE, 0, 0, 0)){
@@ -372,7 +372,7 @@ amata_next_kleene(automaton* amata, const char* prefix, char follow){
   char c;
   while( (c = *prefix++) ){
     if(*amata->matchstart != c){
-      logerror("matchstart didn't match prefix (%c vs %c)\n", c, *amata->matchstart);
+      logerror("matchstart didn't match prefix (%c vs %c)", c, *amata->matchstart);
       return NULL;
     }
     ++amata->matchstart;
@@ -402,7 +402,7 @@ amata_next_numeric(automaton* amata, const char* prefix, char follow){
   char c;
   while( (c = *prefix++) ){
     if(*amata->matchstart != c){
-      logerror("matchstart didn't match prefix (%c vs %c)\n", c, *amata->matchstart);
+      logerror("matchstart didn't match prefix (%c vs %c)", c, *amata->matchstart);
       return 0;
     }
     ++amata->matchstart;
@@ -412,7 +412,7 @@ amata_next_numeric(automaton* amata, const char* prefix, char follow){
   while(isdigit(*amata->matchstart)){
     int addend = *amata->matchstart - '0';
     if((UINT_MAX - addend) / 10 < ret){
-      logerror("overflow: %u * 10 + %u > %u\n", ret, addend, UINT_MAX);
+      logerror("overflow: %u * 10 + %u > %u", ret, addend, UINT_MAX);
     }
     ret *= 10;
     ret += addend;
@@ -420,7 +420,7 @@ amata_next_numeric(automaton* amata, const char* prefix, char follow){
   }
   char candidate = *amata->matchstart++;
   if(candidate != follow){
-    logerror("didn't see follow (%c vs %c)\n", candidate, follow);
+    logerror("didn't see follow (%c vs %c)", candidate, follow);
     return 0;
   }
   return ret;
@@ -448,14 +448,14 @@ mark_pipe_ready(ipipe pipes[static 2]){
   char sig = 1;
 #ifndef __MINGW32__
   if(write(pipes[1], &sig, sizeof(sig)) != 1){
-    logwarn("error writing to pipe (%d) (%s)\n", pipes[1], strerror(errno));
+    logwarn("error writing to pipe (%d) (%s)", pipes[1], strerror(errno));
 #else
   DWORD wrote;
   if(!WriteFile(pipes[1], &sig, sizeof(sig), &wrote, NULL) || wrote != sizeof(sig)){
-    logwarn("error writing to pipe\n");
+    logwarn("error writing to pipe");
 #endif
   }else{
-    loginfo("wrote to readiness pipe\n");
+    loginfo("wrote to readiness pipe");
   }
 }
 
@@ -469,7 +469,7 @@ load_ncinput(inputctx* ictx, const ncinput *tni, int synthsig){
   pthread_mutex_lock(&ictx->ilock);
   if(ictx->ivalid == ictx->isize){
     pthread_mutex_unlock(&ictx->ilock);
-    logwarn("dropping input 0x%08x\n", tni->id);
+    logwarn("dropping input 0x%08x", tni->id);
     inc_input_errors(ictx);
     send_synth_signal(synthsig);
     return;
@@ -501,15 +501,15 @@ mouse_click(inputctx* ictx, unsigned release, char follow){
   y -= (1 + ictx->tmargin);
   // convert from 1- to 0-indexing, and account for margins
   if(x < 0 || y < 0){ // click was in margins, drop it
-    logwarn("dropping click in margins %ld/%ld\n", y, x);
+    logwarn("dropping click in margins %ld/%ld", y, x);
     return;
   }
   if((unsigned)x >= ictx->ti->dimx - (ictx->rmargin + ictx->lmargin)){
-    logwarn("dropping click in margins %ld/%ld\n", y, x);
+    logwarn("dropping click in margins %ld/%ld", y, x);
     return;
   }
   if((unsigned)y >= ictx->ti->dimy - (ictx->bmargin + ictx->tmargin)){
-    logwarn("dropping click in margins %ld/%ld\n", y, x);
+    logwarn("dropping click in margins %ld/%ld", y, x);
     return;
   }
   ncinput tni = {
@@ -571,7 +571,7 @@ cursor_location_cb(inputctx* ictx){
   }
   if(ictx->cvalid == ictx->csize){
     pthread_mutex_unlock(&ictx->clock);
-    logwarn("dropping cursor location report %u/%u\n", y, x);
+    logwarn("dropping cursor location report %u/%u", y, x);
     inc_input_errors(ictx);
   }else{
     cursorloc* cloc = &ictx->csrs[ictx->cwrite];
@@ -583,7 +583,7 @@ cursor_location_cb(inputctx* ictx){
     ++ictx->cvalid;
     pthread_mutex_unlock(&ictx->clock);
     pthread_cond_broadcast(&ictx->ccond);
-    loginfo("cursor location: %u/%u\n", y, x);
+    loginfo("cursor location: %u/%u", y, x);
   }
   return 2;
 }
@@ -598,15 +598,15 @@ geom_cb(inputctx* ictx){
       ictx->initdata->pixy = y;
       ictx->initdata->pixx = x;
     }
-    loginfo("pixel geom report %d/%d\n", y, x);
+    loginfo("pixel geom report %d/%d", y, x);
   }else if(kind == 8){ // cell geometry
     if(ictx->initdata){
       ictx->initdata->dimy = y;
       ictx->initdata->dimx = x;
     }
-    loginfo("cell geom report %d/%d\n", y, x);
+    loginfo("cell geom report %d/%d", y, x);
   }else{
-    logerror("invalid geom report type: %d\n", kind);
+    logerror("invalid geom report type: %d", kind);
     return -1;
   }
   return 2;
@@ -616,7 +616,7 @@ static void
 xtmodkey(inputctx* ictx, int val, int mods){
   assert(mods >= 0);
   assert(val > 0);
-  logdebug("v/m %d %d\n", val, mods);
+  logdebug("v/m %d %d", val, mods);
   ncinput tni = {
     .id = val,
     .evtype = NCTYPE_UNKNOWN,
@@ -680,7 +680,7 @@ kitty_kbd(inputctx* ictx, int val, int mods, int evtype){
   assert(evtype >= 0);
   assert(mods >= 0);
   assert(val > 0);
-  logdebug("v/m/e %d %d %d\n", val, mods, evtype);
+  logdebug("v/m/e %d %d %d", val, mods, evtype);
   ncinput tni = {
     .id = kitty_functional(val),
     .shift = mods && !!((mods - 1) & 0x1),
@@ -964,7 +964,7 @@ kitty_keyboard_cb(inputctx* ictx){
   if(ictx->initdata){
     ictx->initdata->kbdlevel = level;
   }
-  loginfo("kitty keyboard protocol level %u\n", level);
+  loginfo("kitty keyboard protocol level %u", level);
   return 2;
 }
 
@@ -983,7 +983,7 @@ xtsmgraphics_cregs_cb(inputctx* ictx){
   if(ictx->initdata){
     ictx->initdata->color_registers = pv;
   }
-  loginfo("sixel color registers: %d\n", pv);
+  loginfo("sixel color registers: %d", pv);
   return 2;
 }
 
@@ -996,7 +996,7 @@ xtsmgraphics_sixel_cb(inputctx* ictx){
     ictx->initdata->sixelx = width;
     ictx->initdata->sixely = height;
   }
-  loginfo("max sixel geometry: %dx%d\n", height, width);
+  loginfo("max sixel geometry: %dx%d", height, width);
   return 2;
 }
 
@@ -1011,7 +1011,7 @@ handoff_initial_responses_late(inputctx* ictx){
   pthread_mutex_unlock(&ictx->ilock);
   if(sig){
     pthread_cond_broadcast(&ictx->icond);
-    loginfo("handing off initial responses\n");
+    loginfo("handing off initial responses");
   }
 }
 
@@ -1030,7 +1030,7 @@ handoff_initial_responses_early(inputctx* ictx){
 static inline void
 scrub_sixel_responses(struct initial_responses* idata){
   if(idata->color_registers || idata->sixelx || idata->sixely){
-    logwarn("answered XTSMGRAPHICS, but no sixel in DA1\n");
+    logwarn("answered XTSMGRAPHICS, but no sixel in DA1");
     idata->color_registers = 0;
     idata->sixelx = 0;
     idata->sixely = 0;
@@ -1043,7 +1043,7 @@ scrub_sixel_responses(struct initial_responses* idata){
 // so, iff we've determined we're alacritty, don't scrub out Sixel details.
 static int
 da1_vt102_cb(inputctx* ictx){
-  loginfo("read primary device attributes\n");
+  loginfo("read primary device attributes");
   if(ictx->initdata){
     if(ictx->initdata->qterm != TERMINAL_ALACRITTY){
       scrub_sixel_responses(ictx->initdata);
@@ -1055,7 +1055,7 @@ da1_vt102_cb(inputctx* ictx){
 
 static int
 da1_cb(inputctx* ictx){
-  loginfo("read primary device attributes\n");
+  loginfo("read primary device attributes");
   if(ictx->initdata){
     scrub_sixel_responses(ictx->initdata);
     handoff_initial_responses_early(ictx);
@@ -1065,10 +1065,10 @@ da1_cb(inputctx* ictx){
 
 static int
 da1_attrs_cb(inputctx* ictx){
-  loginfo("read primary device attributes\n");
+  loginfo("read primary device attributes");
   unsigned val = amata_next_numeric(&ictx->amata, "\x1b[?", ';');
   char* attrlist = amata_next_kleene(&ictx->amata, "", 'c');
-  logdebug("DA1: %u [%s]\n", val, attrlist);
+  logdebug("DA1: %u [%s]", val, attrlist);
   if(ictx->initdata){
     int foundsixel = 0;
     unsigned curattr = 0;
@@ -1109,19 +1109,19 @@ da2_screen_cb(inputctx* ictx){
     return 2;
   }
   if(ictx->initdata->qterm != TERMINAL_UNKNOWN){
-    logwarn("already identified term (%d)\n", ictx->initdata->qterm);
+    logwarn("already identified term (%d)", ictx->initdata->qterm);
     return 2;
   }
   unsigned ver = amata_next_numeric(&ictx->amata, "\x1b[>83;", ';');
   if(ver < 10000){
-    logwarn("version %u doesn't look like GNU screen\n", ver);
+    logwarn("version %u doesn't look like GNU screen", ver);
     return 2;
   }
   char verstr[9]; // three two-digit components plus two delims
   int s = snprintf(verstr, sizeof(verstr), "%u.%02u.%02u",
                    ver / 10000, ver / 100 % 100, ver % 100);
   if(s < 0 || (unsigned)s >= sizeof(verstr)){
-    logwarn("bad screen version %u\n", ver);
+    logwarn("bad screen version %u", ver);
     return 2;
   }
   ictx->initdata->version = strdup(verstr);
@@ -1133,7 +1133,7 @@ da2_screen_cb(inputctx* ictx){
 // version, and to ascertain the version of old, pre-XTVERSION XTerm.
 static int
 da2_cb(inputctx* ictx){
-  loginfo("read secondary device attributes\n");
+  loginfo("read secondary device attributes");
   if(ictx->initdata == NULL){
     return 2;
   }
@@ -1150,7 +1150,7 @@ da2_cb(inputctx* ictx){
       char ver[8];
       int s = snprintf(ver, sizeof(ver), "%u", pv);
       if(s < 0 || (unsigned)s >= sizeof(ver)){
-        logerror("bad version: %u\n", pv);
+        logerror("bad version: %u", pv);
       }else{
         ictx->initdata->version = strdup(ver);
       }
@@ -1161,14 +1161,14 @@ da2_cb(inputctx* ictx){
   // identify Alacritty. If we've got any other version information, don't
   // use this. use the second parameter (Pv).
   if(ictx->initdata->qterm != TERMINAL_UNKNOWN || ictx->initdata->version){
-    loginfo("termtype was %d %s, not alacritty\n", ictx->initdata->qterm,
+    loginfo("termtype was %d %s, not alacritty", ictx->initdata->qterm,
             ictx->initdata->version);
     return 2;
   }
   // if a termname was manually supplied in setup, it was written to the env
   const char* termname = getenv("TERM");
   if(termname == NULL || strstr(termname, "alacritty") == NULL){
-    loginfo("termname was [%s], probably not alacritty\n",
+    loginfo("termname was [%s], probably not alacritty",
             termname ? termname : "unset");
     return 2;
   }
@@ -1183,7 +1183,7 @@ da2_cb(inputctx* ictx){
   char* buf = malloc(13);
   if(buf){
     sprintf(buf, "%d.%d.%d", maj, min, patch);
-    loginfo("might be alacritty %s\n", buf);
+    loginfo("might be alacritty %s", buf);
     ictx->initdata->version = buf;
     ictx->initdata->qterm = TERMINAL_ALACRITTY;
   }
@@ -1194,14 +1194,14 @@ da2_cb(inputctx* ictx){
 static int
 da3_cb(inputctx* ictx){
   if(ictx->initdata){
-    loginfo("read ternary device attributes\n");
+    loginfo("read ternary device attributes");
   }
   return 2;
 }
 
 static int
 kittygraph_cb(inputctx* ictx){
-  loginfo("kitty graphics message\n");
+  loginfo("kitty graphics message");
   if(ictx->initdata){
     ictx->initdata->kitty_graphics = 1;
   }
@@ -1211,7 +1211,7 @@ kittygraph_cb(inputctx* ictx){
 static int
 decrpm_asu_cb(inputctx* ictx){
   unsigned ps = amata_next_numeric(&ictx->amata, "\x1b[?2026;", '$');
-  loginfo("received decrpm 2026 %u\n", ps);
+  loginfo("received decrpm 2026 %u", ps);
   if(ps == 2){
     if(ictx->initdata){
       ictx->initdata->appsync_supported = 1;
@@ -1230,11 +1230,11 @@ get_default_color(const char* str, uint32_t* color){
     g /= 256;
     b /= 256;
   }else{
-    logerror("couldn't extract rgb from %s\n", str);
+    logerror("couldn't extract rgb from %s", str);
     return -1;
   }
   if(r < 0 || g < 0 || b < 0){
-    logerror("invalid colors %d %d %d\n", r, g, b);
+    logerror("invalid colors %d %d %d", r, g, b);
     return -1;
   }
   *color = (r << 16u) | (g << 8u) | b;
@@ -1246,11 +1246,11 @@ bgdef_cb(inputctx* ictx){
   if(ictx->initdata){
     char* str = amata_next_string(&ictx->amata, "\x1b]11;rgb:");
     if(str == NULL){
-      logerror("empty bg string\n");
+      logerror("empty bg string");
     }else{
       if(get_default_color(str, &ictx->initdata->bg) == 0){
         ictx->initdata->got_bg = true;
-        loginfo("default background 0x%06x\n", ictx->initdata->bg);
+        loginfo("default background 0x%06x", ictx->initdata->bg);
       }
       free(str);
     }
@@ -1263,11 +1263,11 @@ fgdef_cb(inputctx* ictx){
   if(ictx->initdata){
     char* str = amata_next_string(&ictx->amata, "\x1b]10;rgb:");
     if(str == NULL){
-      logerror("empty fg string\n");
+      logerror("empty fg string");
     }else{
       if(get_default_color(str, &ictx->initdata->fg) == 0){
         ictx->initdata->got_fg = true;
-        loginfo("default foreground 0x%06x\n", ictx->initdata->fg);
+        loginfo("default foreground 0x%06x", ictx->initdata->fg);
       }
       free(str);
     }
@@ -1281,15 +1281,15 @@ palette_cb(inputctx* ictx){
     unsigned idx = amata_next_numeric(&ictx->amata, "\x1b]4;", ';');
     char* str = amata_next_string(&ictx->amata, "rgb:");
     if(idx > sizeof(ictx->initdata->palette.chans) / sizeof(*ictx->initdata->palette.chans)){
-      logerror("invalid index %u\n", idx);
+      logerror("invalid index %u", idx);
     }else if(str == NULL){
-      logerror("empty palette string\n");
+      logerror("empty palette string");
     }else{
       if(get_default_color(str, &ictx->initdata->palette.chans[idx]) == 0){
         if((int)idx > ictx->initdata->maxpaletteread){
           ictx->initdata->maxpaletteread = idx;
         }
-        loginfo("index %u 0x%06x\n", idx, ictx->initdata->palette.chans[idx]);
+        loginfo("index %u 0x%06x", idx, ictx->initdata->palette.chans[idx]);
       }
       free(str);
     }
@@ -1301,7 +1301,7 @@ static int
 extract_xtversion(inputctx* ictx, const char* str, char suffix){
   size_t slen = strlen(str);
   if(slen == 0){
-    logwarn("empty version in xtversion\n");
+    logwarn("empty version in xtversion");
     return -1;
   }
   if(suffix){
@@ -1311,7 +1311,7 @@ extract_xtversion(inputctx* ictx, const char* str, char suffix){
     --slen;
   }
   if(slen == 0){
-    logwarn("empty version in xtversion\n");
+    logwarn("empty version in xtversion");
     return -1;
   }
   ictx->initdata->version = strndup(str, slen);
@@ -1325,7 +1325,7 @@ xtversion_cb(inputctx* ictx){
   }
   char* xtversion = amata_next_string(&ictx->amata, "\x1bP>|");
   if(xtversion == NULL){
-    logwarn("empty xtversion\n");
+    logwarn("empty xtversion");
     return 2; // don't replay as input
   }
   static const struct {
@@ -1347,7 +1347,7 @@ xtversion_cb(inputctx* ictx){
   for(xtv = xtvers ; xtv->prefix ; ++xtv){
     if(strncmp(xtversion, xtv->prefix, strlen(xtv->prefix)) == 0){
       if(extract_xtversion(ictx, xtversion + strlen(xtv->prefix), xtv->suffix) == 0){
-        loginfo("found terminal type %d version %s\n", xtv->term, ictx->initdata->version);
+        loginfo("found terminal type %d version %s", xtv->term, ictx->initdata->version);
         ictx->initdata->qterm = xtv->term;
       }else{
         free(xtversion);
@@ -1357,7 +1357,7 @@ xtversion_cb(inputctx* ictx){
     }
   }
   if(xtv->prefix == NULL){
-    logwarn("unknown xtversion [%s]\n", xtversion);
+    logwarn("unknown xtversion [%s]", xtversion);
   }
   free(xtversion);
   return 2;
@@ -1370,7 +1370,7 @@ tcap_cb(inputctx* ictx){
   if(str == NULL){
     return 2;
   }
-  loginfo("xtgettcap [%s]\n", str);
+  loginfo("xtgettcap [%s]", str);
   if(ictx->initdata == NULL){
     free(str);
     return 2;
@@ -1403,14 +1403,14 @@ tcap_cb(inputctx* ictx){
             ictx->initdata->qterm = TERMINAL_XTERM; // "xterm-256color"
           }
         }else{
-          logdebug("unknown terminal name %s\n", tn);
+          logdebug("unknown terminal name %s", tn);
         }
       }
     }else if(strncasecmp(s, "524742=", 7) == 0){
-      loginfo("got rgb (%s)\n", s);
+      loginfo("got rgb (%s)", s);
       ictx->initdata->rgb = true;
     }else{
-      logdebug("unknown capability=val %s\n", str);
+      logdebug("unknown capability=val %s", str);
     }
     if((s = strchr(s, ';')) == NULL){
       break;
@@ -1425,7 +1425,7 @@ static int
 tda_cb(inputctx* ictx){
   char* str = amata_next_string(&ictx->amata, "\x1bP!|");
   if(str == NULL){
-    logwarn("empty ternary device attribute\n");
+    logwarn("empty ternary device attribute");
     return 2; // don't replay
   }
   if(ictx->initdata && ictx->initdata->qterm == TERMINAL_UNKNOWN){
@@ -1436,7 +1436,7 @@ tda_cb(inputctx* ictx){
     }else if(strcmp(str, "464F4F54") == 0){ // "FOOT"
       ictx->initdata->qterm = TERMINAL_FOOT;
     }
-    loginfo("got TDA: %s, terminal type %d\n", str, ictx->initdata->qterm);
+    loginfo("got TDA: %s, terminal type %d", str, ictx->initdata->qterm);
   }
   free(str);
   return 2;
@@ -1524,19 +1524,19 @@ build_cflow_automaton(inputctx* ictx){
   }, *csi;
   for(csi = csis ; csi->cflow ; ++csi){
     if(inputctx_add_cflow(&ictx->amata, csi->cflow, csi->fxn)){
-      logerror("failed adding %p via %s\n", csi->fxn, csi->cflow);
+      logerror("failed adding %p via %s", csi->fxn, csi->cflow);
       return -1;
     }
-    loginfo("added %p via %s\n", csi->fxn, csi->cflow);
+    loginfo("added %p via %s", csi->fxn, csi->cflow);
   }
   if(ictx->ti->qterm == TERMINAL_RXVT){
     if(inputctx_add_cflow(&ictx->amata, "]4;\\N;rgb:\\R", palette_cb)){
-      logerror("failed adding palette_cb\n");
+      logerror("failed adding palette_cb");
       return -1;
     }
   }else{
     if(inputctx_add_cflow(&ictx->amata, "]4;\\N;rgb:\\S", palette_cb)){
-      logerror("failed adding palette_cb\n");
+      logerror("failed adding palette_cb");
       return -1;
     }
   }
@@ -1568,28 +1568,28 @@ getpipes(ipipe pipes[static 2]){
 #ifndef __MINGW32__
 #ifndef __APPLE__
   if(pipe2(pipes, O_CLOEXEC | O_NONBLOCK)){
-    logerror("couldn't get pipes (%s)\n", strerror(errno));
+    logerror("couldn't get pipes (%s)", strerror(errno));
     return -1;
   }
 #else
   if(pipe(pipes)){
-    logerror("couldn't get pipes (%s)\n", strerror(errno));
+    logerror("couldn't get pipes (%s)", strerror(errno));
     return -1;
   }
   if(set_fd_cloexec(pipes[0], 1, NULL) || set_fd_nonblocking(pipes[0], 1, NULL)){
-    logerror("couldn't prep pipe[0] (%s)\n", strerror(errno));
+    logerror("couldn't prep pipe[0] (%s)", strerror(errno));
     endpipes(pipes);
     return -1;
   }
   if(set_fd_cloexec(pipes[1], 1, NULL) || set_fd_nonblocking(pipes[1], 1, NULL)){
-    logerror("couldn't prep pipe[1] (%s)\n", strerror(errno));
+    logerror("couldn't prep pipe[1] (%s)", strerror(errno));
     endpipes(pipes);
     return -1;
   }
 #endif
 #else // windows
   if(!CreatePipe(&pipes[0], &pipes[1], NULL, BUFSIZ)){
-    logerror("couldn't get pipes\n");
+    logerror("couldn't get pipes");
     return -1;
   }
 #endif
@@ -1644,7 +1644,7 @@ create_inputctx(tinfo* ti, FILE* infp, int lmargin, int tmargin, int rmargin,
                             i->bmargin = bmargin;
                             i->drain = drain;
                             i->failed = false;
-                            logdebug("input descriptors: %d/%d\n", i->stdinfd, i->termfd);
+                            logdebug("input descriptors: %d/%d", i->stdinfd, i->termfd);
                             return i;
                           }
                         }
@@ -1725,7 +1725,7 @@ prep_kitty_special_keys(inputctx* ictx){
       return -1;
     }
   }
-  loginfo("added all kitty special keys\n");
+  loginfo("added all kitty special keys");
   return 0;
 }
 
@@ -1774,9 +1774,9 @@ prep_windows_special_keys(inputctx* ictx){
                                  k->shift, k->ctrl, k->alt)){
       return -1;
     }
-    logdebug("added %s %u\n", k->esc, k->key);
+    logdebug("added %s %u", k->esc, k->key);
   }
-  loginfo("added all windows special keys\n");
+  loginfo("added all windows special keys");
   return 0;
 }
 
@@ -1808,9 +1808,9 @@ read_input_nblock(int fd, unsigned char* buf, size_t buflen, int *bufused,
   ssize_t r = read(fd, buf + *bufused, space);
   if(r <= 0){
     if(r < 0){
-      logwarn("couldn't read from %d (%s)\n", fd, strerror(errno));
+      logwarn("couldn't read from %d (%s)", fd, strerror(errno));
     }else{
-      logwarn("got EOF on %d\n", fd);
+      logwarn("got EOF on %d", fd);
       if(goteof){
         *goteof = 1;
       }
@@ -1819,7 +1819,7 @@ read_input_nblock(int fd, unsigned char* buf, size_t buflen, int *bufused,
   }
   *bufused += r;
   space -= r;
-  loginfo("read %" PRIdPTR "B from %d (%" PRIuPTR "B left)\n", r, fd, space);
+  loginfo("read %" PRIdPTR "B from %d (%" PRIuPTR "B left)", r, fd, space);
 }
 
 // are terminal and stdin distinct for this inputctx?
@@ -1856,7 +1856,7 @@ process_escape(inputctx* ictx, const unsigned char* buf, int buflen){
     if(candidate == NCKEY_ESC && !ictx->amata.instring){
       ictx->amata.matchstart = buf + ictx->amata.used - 1;
       ictx->amata.state = ictx->amata.escapes;
-      logtrace("initialized automaton to %u\n", ictx->amata.state);
+      logtrace("initialized automaton to %u", ictx->amata.state);
       ictx->amata.used = 1;
       if(used > 1){ // we got reset; replay as input
         return -(used - 1);
@@ -1868,7 +1868,7 @@ process_escape(inputctx* ictx, const unsigned char* buf, int buflen){
     }else{
       ncinput ni = {0};
       int w = walk_automaton(&ictx->amata, ictx, candidate, &ni);
-      logdebug("walk result on %u (%c): %d %u\n", candidate,
+      logdebug("walk result on %u (%c): %d %u", candidate,
                isprint(candidate) ? candidate : ' ', w, ictx->amata.state);
       if(w > 0){
         if(ni.id){
@@ -1910,7 +1910,7 @@ process_escapes(inputctx* ictx, unsigned char* buf, int* bufused){
           if(available > consumed){
             available = consumed;
           }
-          logwarn("replaying %dB of %dB to ibuf\n", available, consumed);
+          logwarn("replaying %dB of %dB to ibuf", available, consumed);
           memcpy(ictx->ibuf + ictx->ibufvalid, buf + offset, available);
           ictx->ibufvalid += available;
         }
@@ -1945,7 +1945,7 @@ process_input(inputctx* ictx, const unsigned char* buf, int buflen, ncinput* ni)
   memset(ni, 0, sizeof(*ni));
   const int cpointlen = utf8_codepoint_length(*buf);
   if(cpointlen <= 0){
-    logwarn("invalid UTF8 initiator on input (0x%02x)\n", *buf);
+    logwarn("invalid UTF8 initiator on input (0x%02x)", *buf);
     return -1;
   }else if(cpointlen == 1){ // pure ascii can't show up mid-utf8-character
     if(buf[0] == 0x7f || buf[0] == 0x8){ // ASCII del, treated as backspace
@@ -1965,7 +1965,7 @@ process_input(inputctx* ictx, const unsigned char* buf, int buflen, ncinput* ni)
     return 1;
   }
   if(cpointlen > buflen){
-    logwarn("utf8 character (%dB) broken across read\n", cpointlen);
+    logwarn("utf8 character (%dB) broken across read", cpointlen);
     return 0; // need read more data; we don't have the complete character
   }
   wchar_t w;
@@ -1974,7 +1974,7 @@ process_input(inputctx* ictx, const unsigned char* buf, int buflen, ncinput* ni)
   // FIXME how the hell does this work with 16-bit wchar_t?
   size_t r = mbrtowc(&w, (const char*)buf, cpointlen, &mbstate);
   if(r == (size_t)-1 || r == (size_t)-2){
-    logerror("invalid utf8 prefix (%dB) on input\n", cpointlen);
+    logerror("invalid utf8 prefix (%dB) on input", cpointlen);
     return -1;
   }
   ni->id = w;
@@ -1988,7 +1988,7 @@ process_ncinput(inputctx* ictx, const unsigned char* buf, int buflen){
   pthread_mutex_lock(&ictx->ilock);
   if(ictx->ivalid == ictx->isize){
     pthread_mutex_unlock(&ictx->ilock);
-    logwarn("blocking on input output queue (%d+%d)\n", ictx->ivalid, buflen);
+    logwarn("blocking on input output queue (%d+%d)", ictx->ivalid, buflen);
     return 0;
   }
   ncinput* ni = ictx->inputs + ictx->iwrite;
@@ -2040,7 +2040,7 @@ static void
 process_melange(inputctx* ictx, const unsigned char* buf, int* bufused){
   int offset = 0;
   while(*bufused){
-    logdebug("input %d (%u)/%d [0x%02x] (%c)\n", offset, ictx->amata.used,
+    logdebug("input %d (%u)/%d [0x%02x] (%c)", offset, ictx->amata.used,
              *bufused, buf[offset], isprint(buf[offset]) ? buf[offset] : ' ');
     int consumed = 0;
     if(buf[offset] == '\x1b'){
@@ -2112,7 +2112,7 @@ process_ibuf(inputctx* ictx){
 int ncinput_shovel(inputctx* ictx, const void* buf, int len){
   process_melange(ictx, buf, &len);
   if(len){
-    logwarn("dropping %d byte%s\n", len, len == 1 ? "" : "s");
+    logwarn("dropping %d byte%s", len, len == 1 ? "" : "s");
     inc_input_errors(ictx);
   }
   return 0;
@@ -2123,11 +2123,11 @@ int ncinput_shovel(inputctx* ictx, const void* buf, int len){
 // are set high iff they are ready for reading, and otherwise cleared.
 static int
 block_on_input(inputctx* ictx, unsigned* rtfd, unsigned* rifd){
-  logtrace("blocking on input availability\n");
+  logtrace("blocking on input availability");
   *rtfd = *rifd = 0;
   unsigned nonblock = ictx->midescape;
   if(nonblock){
-    loginfo("nonblocking read to check for completion\n");
+    loginfo("nonblocking read to check for completion");
     ictx->midescape = 0;
   }
 #ifdef __MINGW32__
@@ -2168,7 +2168,7 @@ block_on_input(inputctx* ictx, unsigned* rtfd, unsigned* rifd){
     }
   }
   if(pfdcount == 0){
-    loginfo("output queues full; blocking on ipipes\n");
+    loginfo("output queues full; blocking on ipipes");
     pfds[pfdcount].fd = ictx->ipipes[0];
     pfds[pfdcount].events = inevents;
     pfds[pfdcount].revents = 0;
@@ -2180,7 +2180,7 @@ block_on_input(inputctx* ictx, unsigned* rtfd, unsigned* rifd){
     pfds[pfdcount].revents = 0;
     ++pfdcount;
   }
-  logtrace("waiting on %d fds (ibuf: %u/%"PRIuPTR")\n", pfdcount, ictx->ibufvalid, sizeof(ictx->ibuf));
+  logtrace("waiting on %d fds (ibuf: %u/%"PRIuPTR")", pfdcount, ictx->ibufvalid, sizeof(ictx->ibuf));
   sigset_t smask;
   sigfillset(&smask);
   sigdelset(&smask, SIGCONT);
@@ -2200,14 +2200,14 @@ block_on_input(inputctx* ictx, unsigned* rtfd, unsigned* rifd){
   while((events = ppoll(pfds, pfdcount, pts, &smask)) < 0){
 #endif
     if(errno == EINTR){
-      loginfo("interrupted by signal\n");
+      loginfo("interrupted by signal");
       return resize_seen;
     }else if(errno != EAGAIN && errno != EBUSY && errno != EWOULDBLOCK){
-      logerror("error polling (%s)\n", strerror(errno));
+      logerror("error polling (%s)", strerror(errno));
       return -1;
     }
   }
-  loginfo("poll returned %d\n", events);
+  loginfo("poll returned %d", events);
   pfdcount = 0;
   while(events){
     if(pfds[pfdcount].revents){
@@ -2221,7 +2221,7 @@ block_on_input(inputctx* ictx, unsigned* rtfd, unsigned* rifd){
     }
     ++pfdcount;
   }
-  loginfo("got events: %c%c\n", *rtfd ? 'T' : 't', *rifd ? 'I' : 'i');
+  loginfo("got events: %c%c", *rtfd ? 'T' : 't', *rifd ? 'I' : 'i');
   return events;
 #endif
 }
@@ -2275,7 +2275,7 @@ int init_inputlayer(tinfo* ti, FILE* infp, int lmargin, int tmargin,
     return -1;
   }
   ti->ictx = ictx;
-  loginfo("spun up input thread\n");
+  loginfo("spun up input thread");
   return 0;
 }
 
@@ -2285,7 +2285,7 @@ int stop_inputlayer(tinfo* ti){
     // FIXME cancellation on shutdown does not yet work on windows #2192
 #ifndef __MINGW32__
     if(ti->ictx){
-      loginfo("tearing down input thread\n");
+      loginfo("tearing down input thread");
       ret |= cancel_and_join("input", ti->ictx->tid, NULL);
       ret |= set_fd_nonblocking(ti->ictx->stdinfd, ti->stdio_blocking_save, NULL);
       free_inputctx(ti->ictx);
@@ -2301,7 +2301,7 @@ int inputready_fd(const inputctx* ictx){
   return ictx->readypipes[0];
 #else
   (void)ictx;
-  logerror("readiness descriptor unavailable on windows\n");
+  logerror("readiness descriptor unavailable on windows");
   return -1;
 #endif
 }
@@ -2310,7 +2310,7 @@ static inline uint32_t
 internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
   uint32_t id;
   if(ictx->drain){
-    logerror("input is being drained\n");
+    logerror("input is being drained");
     if(ni){
       memset(ni, 0, sizeof(*ni));
       ni->id = (uint32_t)-1;
@@ -2321,7 +2321,7 @@ internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
   while(!ictx->ivalid){
     if(ictx->stdineof){
       pthread_mutex_unlock(&ictx->ilock);
-      logwarn("read eof on stdin\n");
+      logwarn("read eof on stdin");
       if(ni){
         memset(ni, 0, sizeof(*ni));
         ni->id = NCKEY_EOF;
@@ -2362,7 +2362,7 @@ internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
   if(ictx->ivalid-- == ictx->isize){
     sendsignal = true;
   }else{
-    logtrace("draining event readiness pipe %d\n", ictx->ivalid);
+    logtrace("draining event readiness pipe %d", ictx->ivalid);
 #ifndef __MINGW32__
     char c;
     while(read(ictx->readypipes[0], &c, sizeof(c)) == 1){
@@ -2442,7 +2442,7 @@ int get_cursor_location(inputctx* ictx, const char* u7, unsigned* y, unsigned* x
 static int
 linesigs_disable(tinfo* ti){
   if(!ti->ictx->linesigs){
-    logwarn("linedisc signals already disabled\n");
+    logwarn("linedisc signals already disabled");
   }
 #ifndef __MINGW32__
   if(ti->ttyfd < 0){
@@ -2450,28 +2450,28 @@ linesigs_disable(tinfo* ti){
   }
   struct termios tios;
   if(tcgetattr(ti->ttyfd, &tios)){
-    logerror("Couldn't preserve terminal state for %d (%s)\n", ti->ttyfd, strerror(errno));
+    logerror("Couldn't preserve terminal state for %d (%s)", ti->ttyfd, strerror(errno));
     return -1;
   }
   tios.c_lflag &= ~ISIG;
   if(tcsetattr(ti->ttyfd, TCSANOW, &tios)){
-    logerror("Error disabling signals on %d (%s)\n", ti->ttyfd, strerror(errno));
+    logerror("Error disabling signals on %d (%s)", ti->ttyfd, strerror(errno));
     return -1;
   }
 #else
   DWORD mode;
   if(!GetConsoleMode(ti->inhandle, &mode)){
-    logerror("error acquiring input mode\n");
+    logerror("error acquiring input mode");
     return -1;
   }
   mode &= ~ENABLE_PROCESSED_INPUT;
   if(!SetConsoleMode(ti->inhandle, mode)){
-    logerror("error setting input mode\n");
+    logerror("error setting input mode");
     return -1;
   }
 #endif
   ti->ictx->linesigs = 0;
-  loginfo("disabled line discipline signals\n");
+  loginfo("disabled line discipline signals");
   return 0;
 }
 
@@ -2482,7 +2482,7 @@ int notcurses_linesigs_disable(notcurses* nc){
 static int
 linesigs_enable(tinfo* ti){
   if(ti->ictx->linesigs){
-    logwarn("linedisc signals already enabled\n");
+    logwarn("linedisc signals already enabled");
   }
 #ifndef __MINGW32__
   if(ti->ttyfd < 0){
@@ -2490,28 +2490,28 @@ linesigs_enable(tinfo* ti){
   }
   struct termios tios;
   if(tcgetattr(ti->ttyfd, &tios)){
-    logerror("Couldn't preserve terminal state for %d (%s)\n", ti->ttyfd, strerror(errno));
+    logerror("couldn't preserve terminal state for %d (%s)", ti->ttyfd, strerror(errno));
     return -1;
   }
   tios.c_lflag |= ISIG;
   if(tcsetattr(ti->ttyfd, TCSANOW, &tios)){
-    logerror("Error disabling signals on %d (%s)\n", ti->ttyfd, strerror(errno));
+    logerror("error disabling signals on %d (%s)", ti->ttyfd, strerror(errno));
     return -1;
   }
 #else
   DWORD mode;
   if(!GetConsoleMode(ti->inhandle, &mode)){
-    logerror("error acquiring input mode\n");
+    logerror("error acquiring input mode");
     return -1;
   }
   mode |= ENABLE_PROCESSED_INPUT;
   if(!SetConsoleMode(ti->inhandle, mode)){
-    logerror("error setting input mode\n");
+    logerror("error setting input mode");
     return -1;
   }
 #endif
   ti->ictx->linesigs = 1;
-  loginfo("enabled line discipline signals\n");
+  loginfo("enabled line discipline signals");
   return 0;
 }
 
@@ -2531,7 +2531,7 @@ struct initial_responses* inputlayer_get_responses(inputctx* ictx){
   ictx->initdata_complete = NULL;
   pthread_mutex_unlock(&ictx->ilock);
   if(ictx->failed){
-    logpanic("aborting after automaton construction failure\n");
+    logpanic("aborting after automaton construction failure");
     free(iresp);
     return NULL;
   }
diff --git a/src/lib/internal.h b/src/lib/internal.h
index 82c43438d..b48cfb2fa 100644
--- a/src/lib/internal.h
+++ b/src/lib/internal.h
@@ -463,7 +463,7 @@ static inline int
 ncplane_set_widget(ncplane* n, void* w, void(*wdestruct)(void*)){
   if(n->widget){
     if(w){
-      logerror("plane is already bound to a widget\n");
+      logerror("plane is already bound to a widget");
       return -1;
     }
   }else if(w == NULL){
@@ -708,7 +708,7 @@ void sixelmap_free(struct sixelmap *s);
 static inline int
 sprite_scrub(const notcurses* n, const ncpile* p, sprixel* s){
 //sprixel_debug(s, stderr);
-  logdebug("sprixel %u state %d\n", s->id, s->invalidated);
+  logdebug("sprixel %u state %d", s->id, s->invalidated);
   return n->tcache.pixel_scrub(p, s);
 }
 
@@ -721,7 +721,7 @@ sprite_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
     return 0;
   }
 //sprixel_debug(s, stderr);
-  logdebug("sprixel %u state %d\n", s->id, s->invalidated);
+  logdebug("sprixel %u state %d", s->id, s->invalidated);
   return ti->pixel_draw(ti, p, s, f, yoff, xoff);
 }
 
@@ -731,7 +731,7 @@ static inline int
 sprite_redraw(notcurses* nc, const ncpile* p, sprixel* s, fbuf* f, int y, int x){
 //sprixel_debug(s, stderr);
   const tinfo* ti = &nc->tcache;
-  logdebug("sprixel %u state %d\n", s->id, s->invalidated);
+  logdebug("sprixel %u state %d", s->id, s->invalidated);
   if(s->invalidated == SPRIXEL_MOVED && ti->pixel_move){
     // if we are kitty prior to 0.20.0, C=1 isn't available to us, and we must
     // not emit it. we use sixel_maxy_pristine as a side channel to encode
@@ -787,7 +787,7 @@ destroy_tam(ncplane* p){
 
 static inline int
 sprite_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell){
-  logdebug("rebuilding %d %d/%d\n", s->id, ycell, xcell);
+  logdebug("rebuilding %d %d/%d", s->id, ycell, xcell);
   const int idx = s->dimx * ycell + xcell;
   int ret = 0;
   // special case the transition back to SPRIXCELL_TRANSPARENT; this can be
@@ -1456,7 +1456,7 @@ pool_blit_direct(egcpool* pool, nccell* c, const char* gcluster, int bytes, int
   // we allow newlines to be blitted into the pool, as they're picked up and
   // given special semantics by paint() and rasterization.
   if(*gcluster != '\n' && is_control_egc((const unsigned char*)gcluster, bytes)){
-    logerror("not loading control character %u\n", *(const unsigned char*)gcluster);
+    logerror("not loading control character %u", *(const unsigned char*)gcluster);
     return -1;
   }
   c->width = cols;
@@ -1551,14 +1551,14 @@ check_geometry_args(const ncplane* n, int y, int x,
   // handle the special -1 case for y/x, and reject other negatives
   if(y < 0){
     if(y != -1){
-      logerror("invalid y: %d\n", y);
+      logerror("invalid y: %d", y);
       return -1;
     }
     y = n->y;
   }
   if(x < 0){
     if(x != -1){
-      logerror("invalid x: %d\n", x);
+      logerror("invalid x: %d", x);
       return -1;
     }
     x = n->x;
@@ -1570,7 +1570,7 @@ check_geometry_args(const ncplane* n, int y, int x,
   unsigned ymax, xmax;
   ncplane_dim_yx(n, &ymax, &xmax);
   if(*ystart >= ymax || *xstart >= xmax){
-    logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart);
+    logerror("invalid starting coordinates: %u/%u", *ystart, *xstart);
     return -1;
   }
   // handle the special 0 case for ylen/xlen
@@ -1582,20 +1582,20 @@ check_geometry_args(const ncplane* n, int y, int x,
   }
   // ensure ylen/xlen are on-plane
   if(*ylen > ymax){
-    logerror("ylen > dimy %u > %u\n", *ylen, ymax);
+    logerror("ylen > dimy %u > %u", *ylen, ymax);
     return -1;
   }
   if(*xlen > xmax){
-    logerror("xlen > dimx %u > %u\n", *xlen, xmax);
+    logerror("xlen > dimx %u > %u", *xlen, xmax);
     return -1;
   }
   // ensure x + xlen and y + ylen are on-plane, without overflow
   if(ymax - *ylen < *ystart){
-    logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax);
+    logerror("y + ylen > ymax %u + %u > %u", *ystart, *ylen, ymax);
     return -1;
   }
   if(xmax - *xlen < *xstart){
-    logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax);
+    logerror("x + xlen > xmax %u + %u > %u", *xstart, *xlen, xmax);
     return -1;
   }
   return 0;
@@ -1835,10 +1835,10 @@ tty_check(int fd){
 static inline int
 cancel_and_join(const char* name, pthread_t tid, void** res){
   if(pthread_cancel(tid)){
-    logerror("couldn't cancel %s thread\n", name); // tid might have died
+    logerror("couldn't cancel %s thread", name); // tid might have died
   }
   if(pthread_join(tid, res)){
-    logerror("error joining %s thread\n", name);
+    logerror("error joining %s thread", name);
     return -1;
   }
   return 0;
@@ -1846,7 +1846,7 @@ cancel_and_join(const char* name, pthread_t tid, void** res){
 
 static inline int
 emit_scrolls(const tinfo* ti, int count, fbuf* f){
-  logdebug("emitting %d scrolls\n", count);
+  logdebug("emitting %d scrolls", count);
   if(count > 1){
     const char* indn = get_escape(ti, ESCAPE_INDN);
     if(indn){
diff --git a/src/lib/kitty.c b/src/lib/kitty.c
index 39a3196a8..17568ef35 100644
--- a/src/lib/kitty.c
+++ b/src/lib/kitty.c
@@ -337,7 +337,7 @@ kitty_anim_auxvec(int dimy, int dimx, int posy, int posx,
       if(pixels + posx > dimx){
         pixels = dimx - posx;
       }
-      /*logtrace("Copying %d (%d) from %p to %p %d/%d\n",
+      /*logtrace("copying %d (%d) from %p to %p %d/%d",
                pixels * 4, y,
                data + y * (rowstride / 4) + posx,
                a + (y - posy) * (pixels * 4),
@@ -409,7 +409,7 @@ kitty_blit_wipe_selfref(sprixel* s, fbuf* f, int ycell, int xcell){
 // cell id with which we can delete it in O(1) for a rebuild. this
 // way, we needn't delete and redraw the entire sprixel.
 int kitty_wipe_animation(sprixel* s, int ycell, int xcell){
-  logdebug("wiping sprixel %u at %d/%d\n", s->id, ycell, xcell);
+  logdebug("wiping sprixel %u at %d/%d", s->id, ycell, xcell);
   if(init_sprixel_animation(s)){
     return -1;
   }
@@ -431,7 +431,7 @@ int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){
   const int tyx = xcell + ycell * s->dimx;
   int state = s->n->tam[tyx].state;
   void* auxvec = s->n->tam[tyx].auxvector;
-  logdebug("Wiping sprixel %u at %d/%d auxvec: %p state: %d\n", s->id, ycell, xcell, auxvec, state);
+  logdebug("wiping sprixel %u at %d/%d auxvec: %p state: %d", s->id, ycell, xcell, auxvec, state);
   fbuf* f = &s->glyph;
   if(kitty_blit_wipe_selfref(s, f, ycell, xcell)){
     return -1;
@@ -549,7 +549,7 @@ int kitty_wipe(sprixel* s, int ycell, int xcell){
 }
 
 int kitty_commit(fbuf* f, sprixel* s, unsigned noscroll){
-  loginfo("Committing Kitty graphic id %u\n", s->id);
+  loginfo("committing Kitty graphic id %u", s->id);
   int i;
   if(s->pxoffx || s->pxoffy){
     i = fbuf_printf(f, "\e_Ga=p,i=%u,p=1,X=%u,Y=%u%s,q=2\e\\", s->id,
@@ -640,7 +640,7 @@ deflate_buf(void* buf, fbuf* f, int dimy, int dimx){
   // to compress; results per unit time fall off quickly after 2.
   struct libdeflate_compressor* cmp = libdeflate_alloc_compressor(2);
   if(cmp == NULL){
-    logerror("couldn't get libdeflate context\n");
+    logerror("couldn't get libdeflate context");
     return -1;
   }
   // if this allocation fails, just skip compression, no need to bail
@@ -653,13 +653,13 @@ deflate_buf(void* buf, fbuf* f, int dimy, int dimx){
   z_stream zctx = {0};
   int z = deflateInit(&zctx, 2);
   if(z != Z_OK){
-    logerror("couldn't get zlib context\n");
+    logerror("couldn't get zlib context");
     return -1;
   }
   clen = deflateBound(&zctx, blen);
   cbuf = malloc(clen);
   if(cbuf == NULL){
-    logerror("couldn't allocate %" PRIuPTR "B\n", clen);
+    logerror("couldn't allocate %" PRIuPTR "B", clen);
     deflateEnd(&zctx);
     return -1;
   }
@@ -669,7 +669,7 @@ deflate_buf(void* buf, fbuf* f, int dimy, int dimx){
   zctx.avail_in = blen;
   z = deflate(&zctx, Z_FINISH);
   if(z != Z_STREAM_END){
-    logerror("error %d deflating %" PRIuPTR "B -> %" PRIuPTR "B\n", z, blen, clen);
+    logerror("error %d deflating %" PRIuPTR "B -> %" PRIuPTR "B", z, blen, clen);
     deflateEnd(&zctx);
     return -1;
   }
@@ -678,10 +678,10 @@ deflate_buf(void* buf, fbuf* f, int dimy, int dimx){
 #endif
   int ret;
   if(0 == clen){ // wasn't enough room; compressed data is larger than original
-    loginfo("deflated in vain; using original %" PRIuPTR "B\n", blen);
+    loginfo("deflated in vain; using original %" PRIuPTR "B", blen);
     ret = encode_and_chunkify(f, buf, blen, 0);
   }else{
-    loginfo("deflated %" PRIuPTR "B to %" PRIuPTR "B\n", blen, clen);
+    loginfo("deflated %" PRIuPTR "B to %" PRIuPTR "B", blen, clen);
     ret = encode_and_chunkify(f, cbuf, clen, 1);
   }
   free(cbuf);
@@ -748,7 +748,7 @@ finalize_multiframe_selfref(sprixel* s, fbuf* f){
       }
     }
   }
-  loginfo("transitively wiped %d/%u\n", prewiped, s->dimy * s->dimx);
+  loginfo("transitively wiped %d/%u", prewiped, s->dimy * s->dimx);
   return 0;
 }
 
@@ -761,7 +761,7 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
                  const uint32_t* data, const blitterargs* bargs,
                  tament* tam, int* parse_start, ncpixelimpl_e level){
   if(linesize % sizeof(*data)){
-    logerror("stride (%d) badly aligned\n", linesize);
+    logerror("stride (%d) badly aligned", linesize);
     return -1;
   }
   unsigned animated;
@@ -852,7 +852,7 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
                                     data, linesize, tam[tyx].auxvector,
                                     transcolor);
             if(tmp == NULL){
-              logerror("got a NULL auxvec at %d/%d\n", y, x);
+              logerror("got a NULL auxvec at %d/%d", y, x);
               goto err;
             }
             tam[tyx].auxvector = tmp;
@@ -860,7 +860,7 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
             if(tam[tyx].auxvector == NULL){
               tam[tyx].auxvector = malloc(sizeof(tam[tyx].state));
               if(tam[tyx].auxvector == NULL){
-                logerror("got a NULL auxvec at %d\n", tyx);
+                logerror("got a NULL auxvec at %d", tyx);
                 goto err;
               }
             }
@@ -956,7 +956,7 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
   return 0;
 
 err:
-  logerror("failed blitting kitty graphics\n");
+  logerror("failed blitting kitty graphics");
   cleanup_tam(tam, (leny + cdimy - 1) / cdimy, (lenx + cdimx - 1) / cdimx);
   free(buf);
   return -1;
@@ -975,7 +975,7 @@ int kitty_rebuild_selfref(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
   const int xstart = xcell * cellpxx;
   const int xlen = xstart + cellpxx > s->pixx ? s->pixx - xstart : cellpxx;
   const int ylen = ystart + cellpxy > s->pixy ? s->pixy - ystart : cellpxy;
-  logdebug("rematerializing %u at %d/%d (%dx%d)\n", s->id, ycell, xcell, ylen, xlen);
+  logdebug("rematerializing %u at %d/%d (%dx%d)", s->id, ycell, xcell, ylen, xlen);
   fbuf_printf(f, "\e_Ga=c,x=%d,y=%d,X=%d,Y=%d,w=%d,h=%d,i=%d,r=1,c=2,q=2;\x1b\\",
               xcell * cellpxx, ycell * cellpxy,
               xcell * cellpxx, ycell * cellpxy,
@@ -987,7 +987,7 @@ int kitty_rebuild_selfref(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
 }
 
 int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
-  logdebug("rebuilding sprixel %u %d at %d/%d\n", s->id, s->invalidated, ycell, xcell);
+  logdebug("rebuilding sprixel %u %d at %d/%d", s->id, s->invalidated, ycell, xcell);
   if(init_sprixel_animation(s)){
     return -1;
   }
@@ -1008,7 +1008,7 @@ int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
   int targetout = 0; // number of pixels expected out after this chunk
 //fprintf(stderr, "total: %d chunks = %d, s=%d,v=%d\n", total, chunks, lenx, leny);
   // FIXME this ought be factored out and shared with write_kitty_data()
-  logdebug("placing %d/%d at %d/%d\n", ylen, xlen, ycell * cellpxy, xcell * cellpxx);
+  logdebug("placing %d/%d at %d/%d", ylen, xlen, ycell * cellpxy, xcell * cellpxx);
   while(chunks--){
     if(totalout == 0){
       const int c = kitty_anim_auxvec_blitsource_p(s, auxvec) ? 2 : 1;
@@ -1145,7 +1145,7 @@ int kitty_blit_selfref(ncplane* n, int linesize, const void* data,
 }
 
 int kitty_remove(int id, fbuf* f){
-  loginfo("Removing graphic %u\n", id);
+  loginfo("removing graphic %u", id);
   if(fbuf_printf(f, "\e_Ga=d,d=I,i=%d\e\\", id) < 0){
     return -1;
   }
@@ -1194,7 +1194,7 @@ int kitty_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
     animated = true;
   }
   int ret = s->glyph.used;
-  logdebug("dumping %" PRIu64 "b for %u at %d %d\n", s->glyph.used, s->id, yoff, xoff);
+  logdebug("dumping %" PRIu64 "b for %u at %d %d", s->glyph.used, s->id, yoff, xoff);
   if(ret){
     if(fbuf_putn(f, s->glyph.buf, s->glyph.used) < 0){
       ret = -1;
@@ -1211,7 +1211,7 @@ int kitty_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
 int kitty_move(sprixel* s, fbuf* f, unsigned noscroll, int yoff, int xoff){
   const int targy = s->n->absy;
   const int targx = s->n->absx;
-  logdebug("moving %u to %d %d\n", s->id, targy, targx);
+  logdebug("moving %u to %d %d", s->id, targy, targx);
   int ret = 0;
   if(goto_location(ncplane_notcurses(s->n), f, targy + yoff, targx + xoff, s->n)){
     ret = -1;
diff --git a/src/lib/layout.c b/src/lib/layout.c
index 1c44e1448..a7474336a 100644
--- a/src/lib/layout.c
+++ b/src/lib/layout.c
@@ -65,7 +65,7 @@ puttext_line(ncplane* n, ncalign_e align, const char* text, size_t* bytes){
     wchar_t w;
     const size_t consumed = mbrtowc(&w, text + b, MB_CUR_MAX, &mbstate);
     if(consumed == (size_t)-2 || consumed == (size_t)-1){
-      logerror("Invalid UTF-8 after %d bytes\n", b);
+      logerror("invalid UTF-8 after %d bytes", b);
       return -1;
     }
 //fprintf(stderr, "converted [%s] -> %lc\n", text + b, w);
diff --git a/src/lib/linux.c b/src/lib/linux.c
index 09505770c..128dd72c5 100644
--- a/src/lib/linux.c
+++ b/src/lib/linux.c
@@ -162,7 +162,7 @@ int fbcon_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
 }
 
 int fbcon_draw(const tinfo* ti, sprixel* s, int y, int x){
-  logdebug("id %" PRIu32 " dest %d/%d\n", s->id, y, x);
+  logdebug("id %" PRIu32 " dest %d/%d", s->id, y, x);
   int wrote = 0;
   const int cellpxy = ncplane_pile(s->n) ? ncplane_pile(s->n)->cellpxy : ti->cellpxy;
   const int cellpxx = ncplane_pile(s->n) ? ncplane_pile(s->n)->cellpxx : ti->cellpxx;
@@ -197,7 +197,7 @@ void fbcon_scroll(const struct ncpile* p, tinfo* ti, int rows){
   if(cellpxy < 1){
     return;
   }
-  logdebug("scrolling %d\n", rows);
+  logdebug("scrolling %d", rows);
   const int rowbytes = cellpxx * p->dimx * 4;
   const int totalrows = cellpxy * p->dimy;
   int srows = rows * cellpxy; // number of pixel rows being scrolled
@@ -330,7 +330,7 @@ shim_lower_eighths(struct console_font_op* cfo, unsigned idx, int eighths){
 // add UCS2 codepoint |w| to |map| for font idx |fidx|
 static int
 add_to_map(struct unimapdesc* map, wchar_t w, unsigned fidx){
-  logdebug("adding mapping U+%04x -> %03u\n", w, fidx);
+  logdebug("adding mapping U+%04x -> %03u", w, fidx);
   struct unipair* tmp = realloc(map->entries, sizeof(*map->entries) * (map->entry_ct + 1));
   if(tmp == NULL){
     return -1;
@@ -389,7 +389,7 @@ program_line_drawing_chars(int fd, struct unimapdesc* map){
     for(unsigned idx = 0 ; idx < map->entry_ct ; ++idx){
       for(size_t widx = 0 ; widx < wcslen(s->ws) ; ++widx){
         if(map->entries[idx].unicode == s->ws[widx]){
-          logtrace("found desired character U+%04x -> %03u\n",
+          logtrace("found desired character U+%04x -> %03u",
                    map->entries[idx].unicode, map->entries[idx].fontpos);
           found[widx] = true;
           if(fontidx == -1){
@@ -409,7 +409,7 @@ program_line_drawing_chars(int fd, struct unimapdesc* map){
         }
       }
     }else{
-      logwarn("couldn't find any glyphs for set %zu\n", sidx);
+      logwarn("couldn't find any glyphs for set %zu", sidx);
     }
     free(found);
   }
@@ -417,10 +417,10 @@ program_line_drawing_chars(int fd, struct unimapdesc* map){
     return 0;
   }
   if(ioctl(fd, PIO_UNIMAP, map)){
-    logwarn("error setting kernel unicode map (%s)\n", strerror(errno));
+    logwarn("error setting kernel unicode map (%s)", strerror(errno));
     return -1;
   }
-  loginfo("added %d kernel unicode mapping%s\n",
+  loginfo("added %d kernel unicode mapping%s",
           toadd, toadd == 1 ? "" : "s");
   return 0;
 }
@@ -496,7 +496,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
     if(map->entries[i].unicode >= 0x2580 && map->entries[i].unicode <= 0x259f){
       for(size_t s = 0 ; s < sizeof(half) / sizeof(*half) ; ++s){
         if(map->entries[i].unicode == half[s].w){
-          logdebug("found %lc at fontidx %u\n", half[s].w, i);
+          logdebug("found %lc at fontidx %u", half[s].w, i);
           half[s].found = true;
           ++halvesfound;
           break;
@@ -504,7 +504,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
       }
       for(size_t s = 0 ; s < sizeof(quads) / sizeof(*quads) ; ++s){
         if(map->entries[i].unicode == quads[s].w){
-          logdebug("found %lc at fontidx %u\n", quads[s].w, i);
+          logdebug("found %lc at fontidx %u", quads[s].w, i);
           quads[s].found = true;
           ++numfound;
           break;
@@ -512,7 +512,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
       }
       for(size_t s = 0 ; s < sizeof(eighths) / sizeof(*eighths) ; ++s){
         if(map->entries[i].unicode == eighths[s].w){
-          logdebug("found %lc at fontidx %u\n", eighths[s].w, i);
+          logdebug("found %lc at fontidx %u", eighths[s].w, i);
           eighths[s].found = true;
           ++numfound;
           break;
@@ -524,12 +524,12 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
     *halfblocks = true;
   }
   if(numfound + halvesfound == (sizeof(half) + sizeof(quads) + sizeof(eighths)) / sizeof(*quads)){
-    logdebug("all %zu desired glyphs were already present\n", numfound);
+    logdebug("all %zu desired glyphs were already present", numfound);
     *quadrants = true;
     return 0;
   }
   if(no_font_changes){
-    logdebug("not reprogramming kernel font per request\n");
+    logdebug("not reprogramming kernel font per request");
     return 0;
   }
   int added = 0;
@@ -544,12 +544,12 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
         }
       }
       if(candidate == 0){
-        logwarn("ran out of replaceable glyphs for U+%04lx\n", (long)half[s].w);
+        logwarn("ran out of replaceable glyphs for U+%04lx", (long)half[s].w);
         // FIXME maybe don't want to error out here?
         return -1;
       }
       if(shim_quad_block(cfo, candidate, half[s].qbits)){
-        logwarn("error replacing glyph for U+%04lx at %u\n", (long)half[s].w, candidate);
+        logwarn("error replacing glyph for U+%04lx at %u", (long)half[s].w, candidate);
         return -1;
       }
       if(add_to_map(map, half[s].w, candidate)){
@@ -566,12 +566,12 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
         }
       }
       if(candidate == 0){
-        logwarn("ran out of replaceable glyphs for U+%04lx\n", (long)quads[s].w);
+        logwarn("ran out of replaceable glyphs for U+%04lx", (long)quads[s].w);
         // FIXME maybe don't want to error out here?
         return -1;
       }
       if(shim_quad_block(cfo, candidate, quads[s].qbits)){
-        logwarn("error replacing glyph for U+%04lx at %u\n", (long)quads[s].w, candidate);
+        logwarn("error replacing glyph for U+%04lx at %u", (long)quads[s].w, candidate);
         return -1;
       }
       if(add_to_map(map, quads[s].w, candidate)){
@@ -588,11 +588,11 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
         }
       }
       if(candidate == 0){
-        logwarn("ran out of replaceable glyphs for U+%04lx\n", (long)eighths[s].w);
+        logwarn("ran out of replaceable glyphs for U+%04lx", (long)eighths[s].w);
         return -1;
       }
       if(shim_lower_eighths(cfo, candidate, eighths[s].qbits)){
-        logwarn("error replacing glyph for U+%04lx at %u\n", (long)eighths[s].w, candidate);
+        logwarn("error replacing glyph for U+%04lx at %u", (long)eighths[s].w, candidate);
         return -1;
       }
       if(add_to_map(map, eighths[s].w, candidate)){
@@ -602,7 +602,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
     }
   }
   if(halvesadded == 0 && added == 0){
-    loginfo("didn't replace any glyphs, not calling ioctl\n");
+    loginfo("didn't replace any glyphs, not calling ioctl");
     return 0;
   }
   struct framebuffer_copy fbdup;
@@ -611,12 +611,12 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
   }
   cfo->op = KD_FONT_OP_SET;
   if(ioctl(fd, KDFONTOP, cfo)){
-    logwarn("error programming kernel font (%s)\n", strerror(errno));
+    logwarn("error programming kernel font (%s)", strerror(errno));
     kill_fbcopy(&fbdup);
     return -1;
   }
   if(ioctl(fd, PIO_UNIMAP, map)){
-    logwarn("error setting kernel unicode map (%s)\n", strerror(errno));
+    logwarn("error setting kernel unicode map (%s)", strerror(errno));
     kill_fbcopy(&fbdup);
     return -1;
   }
@@ -627,7 +627,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
     *quadrants = true;
   }
   added += halvesadded;
-  loginfo("successfully added %d kernel font glyph%s via %d\n", added, added == 1 ? "" : "s", ti->linux_fb_fd);
+  loginfo("successfully added %d kernel font glyph%s via %d", added, added == 1 ? "" : "s", ti->linux_fb_fd);
   if(ti->linux_fb_fd < 0){ // console doesn't imply framebuffer
     kill_fbcopy(&fbdup);
     return 0;
@@ -638,7 +638,7 @@ program_block_drawing_chars(tinfo* ti, int fd, struct console_font_op* cfo,
     return -1;
   }
   if(pixely != fbdup.pixely || pixelx != fbdup.pixelx || ti->linux_fb_len != fbdup.maplen){
-    logwarn("framebuffer changed size, not reblitting\n");
+    logwarn("framebuffer changed size, not reblitting");
   }else{
     memcpy(ti->linux_fbuffer, fbdup.map, fbdup.maplen);
   }
@@ -651,20 +651,20 @@ reprogram_linux_font(tinfo* ti, int fd, struct console_font_op* cfo,
                      struct unimapdesc* map, unsigned no_font_changes,
                      bool* halfblocks, bool* quadrants){
   if(ioctl(fd, KDFONTOP, cfo)){
-    logwarn("error reading Linux kernelfont (%s)\n", strerror(errno));
+    logwarn("error reading Linux kernelfont (%s)", strerror(errno));
     return -1;
   }
-  loginfo("kernel font size (glyphcount): %u\n", cfo->charcount);
-  loginfo("kernel font character geometry: %ux%u\n", cfo->width, cfo->height);
+  loginfo("kernel font size (glyphcount): %u", cfo->charcount);
+  loginfo("kernel font character geometry: %ux%u", cfo->width, cfo->height);
   if(cfo->charcount > 512){
-    logwarn("warning: kernel returned excess charcount\n");
+    logwarn("warning: kernel returned excess charcount");
     return -1;
   }
   if(ioctl(fd, GIO_UNIMAP, map)){
-    logwarn("error reading Linux unimap (%s)\n", strerror(errno));
+    logwarn("error reading Linux unimap (%s)", strerror(errno));
     return -1;
   }
-  loginfo("kernel unimap size: %u/%u\n", map->entry_ct, USHRT_MAX);
+  loginfo("kernel unimap size: %u/%u", map->entry_ct, USHRT_MAX);
   // for certain sets of characters, we're not going to draw them in, but we
   // do want to ensure they map to something plausible...this doesn't reset
   // the framebuffer, even if we do some reprogramming.
@@ -691,7 +691,7 @@ int reprogram_console_font(tinfo* ti, unsigned no_font_changes,
   size_t totsize = 128 * cfo.charcount; // FIXME enough?
   cfo.data = malloc(totsize);
   if(cfo.data == NULL){
-    logwarn("error acquiring %zub for font descriptors (%s)\n", totsize, strerror(errno));
+    logwarn("error acquiring %zub for font descriptors (%s)", totsize, strerror(errno));
     return -1;
   }
   struct unimapdesc map = {0};
@@ -699,7 +699,7 @@ int reprogram_console_font(tinfo* ti, unsigned no_font_changes,
   totsize = map.entry_ct * sizeof(struct unipair);
   map.entries = malloc(totsize);
   if(map.entries == NULL){
-    logwarn("error acquiring %zub for Unicode font map (%s)\n", totsize, strerror(errno));
+    logwarn("error acquiring %zub for Unicode font map (%s)", totsize, strerror(errno));
     free(cfo.data);
     return -1;
   }
@@ -719,10 +719,10 @@ bool is_linux_console(int fd){
   }
   int mode;
   if(ioctl(fd, KDGETMODE, &mode)){
-    logdebug("not a Linux console (no KDGETMODE)\n");
+    logdebug("not a Linux console (no KDGETMODE)");
     return false;
   }
-  loginfo("verified Linux console, mode %d\n", mode);
+  loginfo("verified Linux console, mode %d", mode);
   return true;
 }
 
@@ -736,11 +736,11 @@ int get_linux_fb_pixelgeom(tinfo* ti, unsigned* ypix, unsigned *xpix){
   }
   struct fb_var_screeninfo fbi = {0};
   if(ioctl(ti->linux_fb_fd, FBIOGET_VSCREENINFO, &fbi)){
-    logerror("no framebuffer info from %s %d (%s?)\n", ti->linux_fb_dev,
+    logerror("no framebuffer info from %s %d (%s?)", ti->linux_fb_dev,
              ti->linux_fb_fd, strerror(errno));
     return -1;
   }
-  loginfo("linux %s geometry: %dx%d\n", ti->linux_fb_dev, fbi.yres, fbi.xres);
+  loginfo("linux %s geometry: %dx%d", ti->linux_fb_dev, fbi.yres, fbi.xres);
   *ypix = fbi.yres;
   *xpix = fbi.xres;
   size_t len = *ypix * *xpix * fbi.bits_per_pixel / 8;
@@ -753,11 +753,11 @@ int get_linux_fb_pixelgeom(tinfo* ti, unsigned* ypix, unsigned *xpix){
     ti->linux_fbuffer = mmap(NULL, len, PROT_READ|PROT_WRITE,
                              MAP_SHARED, ti->linux_fb_fd, 0);
     if(ti->linux_fbuffer == MAP_FAILED){
-      logerror("couldn't map %zuB on %s (%s?)\n", len, ti->linux_fb_dev, strerror(errno));
+      logerror("couldn't map %zuB on %s (%s?)", len, ti->linux_fb_dev, strerror(errno));
       return -1;
     }
     ti->linux_fb_len = len;
-    loginfo("mapped %zuB on %s\n", len, ti->linux_fb_dev);
+    loginfo("mapped %zuB on %s", len, ti->linux_fb_dev);
   }
   return 0;
 }
@@ -766,10 +766,10 @@ bool is_linux_framebuffer(tinfo* ti){
   // FIXME there might be multiple framebuffers present; how do we determine
   // which one is ours?
   const char* dev = "/dev/fb0";
-  loginfo("checking for Linux framebuffer at %s\n", dev);
+  loginfo("checking for Linux framebuffer at %s", dev);
   int fd = open(dev, O_RDWR | O_CLOEXEC);
   if(fd < 0){
-    logdebug("couldn't open framebuffer device %s\n", dev);
+    logdebug("couldn't open framebuffer device %s", dev);
     return false;
   }
   ti->linux_fb_fd = fd;
diff --git a/src/lib/logging.h b/src/lib/logging.h
index 11ad244a3..8f01ffcfb 100644
--- a/src/lib/logging.h
+++ b/src/lib/logging.h
@@ -12,42 +12,42 @@ extern int loglevel;
 
 #define logpanic(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_PANIC){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logfatal(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_FATAL){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logerror(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_ERROR){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logwarn(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_WARNING){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define loginfo(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_INFO){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logverbose(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_VERBOSE){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logdebug(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_DEBUG){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #define logtrace(fmt, ...) do{ \
   if(loglevel >= NCLOGLEVEL_TRACE){ \
-    nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } \
+    nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \
   } while(0);
 
 #ifdef __cplusplus
diff --git a/src/lib/menu.c b/src/lib/menu.c
index 05cc106f5..92ab3f4c9 100644
--- a/src/lib/menu.c
+++ b/src/lib/menu.c
@@ -380,11 +380,11 @@ ncmenu* ncmenu_create(ncplane* n, const ncmenu_options* opts){
     opts = &zeroed;
   }
   if(opts->sectioncount <= 0 || !opts->sections){
-    logerror("Invalid %d-ary section information\n", opts->sectioncount);
+    logerror("invalid %d-ary section information", opts->sectioncount);
     return NULL;
   }
   if(opts->flags >= (NCMENU_OPTION_HIDING << 1u)){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
   unsigned totalheight = 1;
   unsigned totalwidth = 2; // start with two-character margin on the left
@@ -435,7 +435,7 @@ ncmenu* ncmenu_create(ncplane* n, const ncmenu_options* opts){
     }
     free(ret);
   }
-  logerror("Error creating ncmenu\n");
+  logerror("error creating ncmenu");
   return NULL;
 }
 
@@ -454,7 +454,7 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
     return -1;
   }
   if(sectionidx < 0 || sectionidx >= n->sectioncount){
-    logerror("Unrolled invalid sectionidx %d\n", sectionidx);
+    logerror("unrolled invalid sectionidx %d", sectionidx);
     return -1;
   }
   if(n->sections[sectionidx].enabled_item_count <= 0){
diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c
index 2f4b816b4..12fdc6fad 100644
--- a/src/lib/notcurses.c
+++ b/src/lib/notcurses.c
@@ -78,7 +78,7 @@ int reset_term_palette(const tinfo* ti, fbuf* f, unsigned touchedpalette){
   int ret = 0;
   const char* esc;
   if((esc = get_escape(ti, ESCAPE_RESTORECOLORS))){
-    loginfo("restoring palette via xtpopcolors\n");
+    loginfo("restoring palette via xtpopcolors");
     if(fbuf_emit(f, esc)){
       ret = -1;
     }
@@ -88,7 +88,7 @@ int reset_term_palette(const tinfo* ti, fbuf* f, unsigned touchedpalette){
     return 0;
   }
   if(ti->caps.can_change_colors && ti->maxpaletteread > -1){
-    loginfo("restoring saved palette (%d)\n", ti->maxpaletteread + 1);
+    loginfo("restoring saved palette (%d)", ti->maxpaletteread + 1);
     esc = get_escape(ti, ESCAPE_INITC);
     for(int z = 0 ; z < ti->maxpaletteread ; ++z){
       unsigned r, g, b;
@@ -102,12 +102,12 @@ int reset_term_palette(const tinfo* ti, fbuf* f, unsigned touchedpalette){
       }
     }
   }else if((esc = get_escape(ti, ESCAPE_OC))){
-    loginfo("resetting palette\n");
+    loginfo("resetting palette");
     if(fbuf_emit(f, esc)){
       ret = -1;
     }
   }else{
-    logwarn("no method known to restore palette\n");
+    logwarn("no method known to restore palette");
   }
   return ret;
 }
@@ -169,7 +169,7 @@ notcurses_stop_minimal(void* vnc){
       }
     }
   }
-  logdebug("restored terminal, returning %d\n", ret);
+  logdebug("restored terminal, returning %d", ret);
   return ret;
 }
 
@@ -213,20 +213,20 @@ char* ncplane_at_cursor(ncplane* n, uint16_t* stylemask, uint64_t* channels){
 char* ncplane_at_yx(const ncplane* n, int y, int x, uint16_t* stylemask, uint64_t* channels){
   if(y < 0){
     if(y != -1){
-      logerror("invalid y: %d\n", y);
+      logerror("invalid y: %d", y);
       return NULL;
     }
     y = n->y;
   }
   if(x < 0){
     if(x != -1){
-      logerror("invalid x: %d\n", x);
+      logerror("invalid x: %d", x);
       return NULL;
     }
     x = n->x;
   }
   if((unsigned)y >= n->leny || (unsigned)x >= n->lenx){
-    logerror("invalid coordinates: %d/%d\n", y, x);
+    logerror("invalid coordinates: %d/%d", y, x);
     return NULL;
   }
   const nccell* yx = &n->fb[nfbcellidx(n, y, x)];
@@ -260,20 +260,20 @@ int ncplane_at_cursor_cell(ncplane* n, nccell* c){
 int ncplane_at_yx_cell(ncplane* n, int y, int x, nccell* c){
   if(y < 0){
     if(y != -1){
-      logerror("invalid y: %d\n", y);
+      logerror("invalid y: %d", y);
       return -1;
     }
     y = n->y;
   }
   if(x < 0){
     if(x != -1){
-      logerror("invalid x: %d\n", x);
+      logerror("invalid x: %d", x);
       return -1;
     }
     x = n->x;
   }
   if((unsigned)y >= n->leny || (unsigned)x >= n->lenx){
-    logerror("invalid coordinates: %d/%d\n", y, x);
+    logerror("invalid coordinates: %d/%d", y, x);
     return -1;
   }
   nccell* targ = ncplane_cell_ref_yx(n, y, x);
@@ -467,9 +467,9 @@ void free_plane(ncplane* p){
       void (*wdestruct)(void*) = p->wdestruct;
       p->widget = NULL;
       p->wdestruct = NULL;
-      logdebug("calling widget destructor %p(%p)\n", wdestruct, w);
+      logdebug("calling widget destructor %p(%p)", wdestruct, w);
       wdestruct(w);
-      logdebug("got the widget\n");
+      logdebug("got the widget");
     }
     if(p->sprite){
       sprixel_hide(p->sprite);
@@ -533,22 +533,22 @@ make_ncpile(notcurses* nc, ncplane* n){
 ncplane* ncplane_new_internal(notcurses* nc, ncplane* n,
                               const ncplane_options* nopts){
   if(nopts->flags >= (NCPLANE_OPTION_FIXED << 1u)){
-    logwarn("provided unsupported flags %016" PRIx64 "\n", nopts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, nopts->flags);
   }
   if(nopts->flags & NCPLANE_OPTION_HORALIGNED || nopts->flags & NCPLANE_OPTION_VERALIGNED){
     if(n == NULL){
-      logerror("alignment requires a parent plane\n");
+      logerror("alignment requires a parent plane");
       return NULL;
     }
   }
   if(nopts->flags & NCPLANE_OPTION_MARGINALIZED){
     if(nopts->rows != 0 || nopts->cols != 0){
-      logerror("geometry specified with margins (r=%d, c=%d)\n",
+      logerror("geometry specified with margins (r=%d, c=%d)",
                nopts->rows, nopts->cols);
       return NULL;
     }
   }else if(nopts->rows <= 0 || nopts->cols <= 0){
-    logerror("won't create denormalized plane (r=%d, c=%d)\n",
+    logerror("won't create denormalized plane (r=%d, c=%d)",
              nopts->rows, nopts->cols);
     return NULL;
   }
@@ -582,7 +582,7 @@ ncplane* ncplane_new_internal(notcurses* nc, ncplane* n,
   }
   size_t fbsize = sizeof(*p->fb) * (p->leny * p->lenx);
   if((p->fb = malloc(fbsize)) == NULL){
-    logerror("error allocating cellmatrix (r=%d, c=%d)\n",
+    logerror("error allocating cellmatrix (r=%d, c=%d)",
              p->leny, p->lenx);
     free(p);
     return NULL;
@@ -655,7 +655,7 @@ ncplane* ncplane_new_internal(notcurses* nc, ncplane* n,
       pthread_mutex_unlock(&nc->stats.lock);
     pthread_mutex_unlock(&nc->pilelock);
   }
-  loginfo("created new %dx%d plane \"%s\" @ %dx%d\n",
+  loginfo("created new %dx%d plane \"%s\" @ %dx%d",
           p->leny, p->lenx, p->name ? p->name : "", p->absy, p->absx);
   return p;
 }
@@ -700,28 +700,28 @@ void ncplane_home(ncplane* n){
 int ncplane_cursor_move_yx(ncplane* n, int y, int x){
   if(x < 0){
     if(x < -1){
-      logerror("negative target x %d\n", x);
+      logerror("negative target x %d", x);
       return -1;
     }
   }else if((unsigned)x >= n->lenx){
-    logerror("target x %d >= width %u\n", x, n->lenx);
+    logerror("target x %d >= width %u", x, n->lenx);
     return -1;
   }else{
     n->x = x;
   }
   if(y < 0){
     if(y < -1){
-      logerror("negative target y %d\n", y);
+      logerror("negative target y %d", y);
       return -1;
     }
   }else if((unsigned)y >= n->leny){
-    logerror("target y %d >= height %u\n", y, n->leny);
+    logerror("target y %d >= height %u", y, n->leny);
     return -1;
   }else{
     n->y = y;
   }
   if(cursor_invalid_p(n)){
-    logerror("invalid cursor following move (%d/%d)\n", n->y, n->x);
+    logerror("invalid cursor following move (%d/%d)", n->y, n->x);
     return -1;
   }
   return 0;
@@ -729,10 +729,10 @@ int ncplane_cursor_move_yx(ncplane* n, int y, int x){
 
 int ncplane_cursor_move_rel(ncplane* n, int y, int x){
   if((int)n->y + y == -1){
-    logerror("invalid target y -1\n");
+    logerror("invalid target y -1");
     return -1;
   }else if((int)n->x + x == -1){
-    logerror("invalid target x -1\n");
+    logerror("invalid target x -1");
     return -1;
   }else return ncplane_cursor_move_yx(n, n->y + y, n->x + x);
 }
@@ -794,37 +794,37 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx,
                             int yoff, int xoff,
                             unsigned ylen, unsigned xlen){
   if(keepy < 0 || keepx < 0){ // can't start at negative origin
-    logerror("can't retain negative offset %dx%d\n", keepy, keepx);
+    logerror("can't retain negative offset %dx%d", keepy, keepx);
     return -1;
   }
   if((!keepleny && keeplenx) || (keepleny && !keeplenx)){ // both must be 0
-    logerror("can't retain null dimension %dx%d\n", keepleny, keeplenx);
+    logerror("can't retain null dimension %dx%d", keepleny, keeplenx);
     return -1;
   }
   // can't be smaller than keep length
   if(ylen < keepleny){
-    logerror("can't map in y dimension: %u < %d\n", ylen, keepleny);
+    logerror("can't map in y dimension: %u < %d", ylen, keepleny);
     return -1;
   }
   if(xlen < keeplenx){
-    logerror("can't map in x dimension: %u < %d\n", xlen, keeplenx);
+    logerror("can't map in x dimension: %u < %d", xlen, keeplenx);
     return -1;
   }
   if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size
-    logerror("can't achieve meaningless size %ux%u\n", ylen, xlen);
+    logerror("can't achieve meaningless size %ux%u", ylen, xlen);
     return -1;
   }
   unsigned rows, cols;
   ncplane_dim_yx(n, &rows, &cols);
   if(keepleny + keepy > rows){
-    logerror("can't keep %d@%d rows from %d\n", keepleny, keepy, rows);
+    logerror("can't keep %d@%d rows from %d", keepleny, keepy, rows);
     return -1;
   }
   if(keeplenx + keepx > cols){
-    logerror("can't keep %d@%d cols from %d\n", keeplenx, keepx, cols);
+    logerror("can't keep %d@%d cols from %d", keeplenx, keepx, cols);
     return -1;
   }
-  loginfo("%dx%d @ %d/%d → %u/%u @ %d/%d (want %ux%u@%d/%d)\n", rows, cols, n->absy, n->absx, ylen, xlen, n->absy + keepy + yoff, n->absx + keepx + xoff, keepleny, keeplenx, keepy, keepx);
+  loginfo("%dx%d @ %d/%d → %u/%u @ %d/%d (want %ux%u@%d/%d)", rows, cols, n->absy, n->absx, ylen, xlen, n->absy + keepy + yoff, n->absx + keepx + xoff, keepleny, keeplenx, keepy, keepx);
   if(n->absy == n->absy + keepy && n->absx == n->absx + keepx &&
       rows == ylen && cols == xlen){
     return 0;
@@ -879,7 +879,7 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx,
     }
   }
   if(n->tam){
-    loginfo("TAM realloc to %d entries\n", newarea);
+    loginfo("tam realloc to %d entries", newarea);
     // FIXME first, free any disposed auxiliary vectors!
     tament* tmptam = realloc(n->tam, sizeof(*tmptam) * newarea);
     if(tmptam == NULL){
@@ -984,11 +984,11 @@ int ncplane_destroy(ncplane* ncp){
     return 0;
   }
   if(ncplane_notcurses(ncp)->stdplane == ncp){
-    logerror("Won't destroy standard plane\n");
+    logerror("won't destroy standard plane");
     return -1;
   }
 //notcurses_debug(ncplane_notcurses(ncp), stderr);
-  loginfo("Destroying %dx%d plane \"%s\" @ %dx%d\n",
+  loginfo("destroying %dx%d plane \"%s\" @ %dx%d",
           ncp->leny, ncp->lenx, ncp->name ? ncp->name : NULL, ncp->absy, ncp->absx);
   int ret = 0;
   // dissolve our binding from behind (->bprev is either NULL, or its
@@ -1034,7 +1034,7 @@ int ncplane_destroy_family(ncplane *ncp){
     return 0;
   }
   if(ncplane_notcurses(ncp)->stdplane == ncp){
-    logerror("Won't destroy standard plane\n");
+    logerror("won't destroy standard plane");
     return -1;
   }
   int ret = 0;
@@ -1059,7 +1059,7 @@ void init_lang(void){
   char* setret;
 #ifdef __MINGW32__
   if((setret = setlocale(LC_ALL, ".UTF8")) == NULL){
-    logwarn("couldn't set LC_ALL to utf8\n");
+    logwarn("couldn't set LC_ALL to utf8");
   }
 #endif
   const char* encoding = nl_langinfo(CODESET);
@@ -1069,23 +1069,23 @@ void init_lang(void){
   const char* lang = getenv("LANG");
   // if LANG was explicitly set to C/POSIX, life sucks, roll with it
   if(lang && (!strcmp(lang, "C") || !strcmp(lang, "POSIX"))){
-    loginfo("LANG was explicitly set to %s, not changing locale\n", lang);
+    loginfo("LANG was explicitly set to %s, not changing locale", lang);
     return;
   }
 #ifndef __MINGW32__
   if((setret = setlocale(LC_ALL, "")) == NULL){
-    logwarn("setting locale based on LANG failed\n");
+    logwarn("setting locale based on LANG failed");
   }
 #endif
   encoding = nl_langinfo(CODESET);
   if(encoding && !strcmp(encoding, "UTF-8")){
-    loginfo("Set locale from LANG; client should call setlocale(2)!\n");
+    loginfo("set locale from LANG; client should call setlocale(2)!");
     return;
   }
   setlocale(LC_CTYPE, "C.UTF-8");
   encoding = nl_langinfo(CODESET);
   if(encoding && !strcmp(encoding, "UTF-8")){
-    loginfo("Forced UTF-8 encoding; client should call setlocale(2)!\n");
+    loginfo("forced UTF-8 encoding; client should call setlocale(2)!");
     return;
   }
 }
@@ -1131,7 +1131,7 @@ ncpixelimpl_e notcurses_check_pixel_support(const notcurses* nc){
 __attribute__ ((nonnull (2))) static notcurses*
 notcurses_early_init(const struct notcurses_options* opts, FILE* fp, unsigned* utf8){
   if(fwide(fp, 0) > 0){
-    fprintf(stderr, "Error: output stream is wide-oriented\n");
+    fprintf(stderr, "error: output stream is wide-oriented");
     return NULL;
   }
   notcurses* ret = malloc(sizeof(*ret));
@@ -1141,7 +1141,7 @@ notcurses_early_init(const struct notcurses_options* opts, FILE* fp, unsigned* u
   memset(ret, 0, sizeof(*ret));
   if(opts){
     if(opts->flags >= (NCOPTION_DRAIN_INPUT << 1u)){
-      fprintf(stderr, "Warning: unknown Notcurses options %016" PRIu64 "\n", opts->flags);
+      fprintf(stderr, "warning: unknown Notcurses options %016" PRIu64, opts->flags);
     }
     if(opts->termtype){
       if(putenv_term(opts->termtype)){
@@ -1169,7 +1169,7 @@ notcurses_early_init(const struct notcurses_options* opts, FILE* fp, unsigned* u
     if(encoding && (strcmp(encoding, "ANSI_X3.4-1968") &&
                           strcmp(encoding, "US-ASCII") &&
                           strcmp(encoding, "ASCII"))){
-      fprintf(stderr, "Encoding (\"%s\") was neither ANSI_X3.4-1968 nor UTF-8, refusing to start\n Did you call setlocale()?\n",
+      fprintf(stderr, "encoding (\"%s\") was neither ANSI_X3.4-1968 nor UTF-8, refusing to start\n did you call setlocale()?\n",
               encoding ? encoding : "none found");
       free(ret);
       return NULL;
@@ -1181,12 +1181,12 @@ notcurses_early_init(const struct notcurses_options* opts, FILE* fp, unsigned* u
   ret->ttyfp = fp;
   egcpool_init(&ret->pool);
   if(ret->loglevel > NCLOGLEVEL_TRACE || ret->loglevel < NCLOGLEVEL_SILENT){
-    fprintf(stderr, "Invalid loglevel %d\n", ret->loglevel);
+    fprintf(stderr, "invalid loglevel %d", ret->loglevel);
     free(ret);
     return NULL;
   }
   if(recursive_lock_init(&ret->pilelock)){
-    fprintf(stderr, "Couldn't initialize pile mutex\n");
+    fprintf(stderr, "couldn't initialize pile mutex");
     free(ret);
     return NULL;
   }
@@ -1263,7 +1263,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
     if(*cursory < 0 || *cursorx < 0){
       unsigned cy, cx;
       if(locate_cursor(&ret->tcache, &cy, &cx)){
-        logwarn("couldn't preserve cursor\n");
+        logwarn("couldn't preserve cursor");
       }else{
         *cursory = cy;
         *cursorx = cx;
@@ -1284,7 +1284,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
   }
   ret->stdplane = NULL;
   if((ret->stdplane = create_initial_ncplane(ret, dimy, dimx)) == NULL){
-    logpanic("Couldn't create the initial plane (bad margins?)\n");
+    logpanic("couldn't create the initial plane (bad margins?)");
     goto err;
   }
   reset_term_attributes(&ret->tcache, &ret->rstate.f);
@@ -1342,7 +1342,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
   return ret;
 
 err:
-  logpanic("Alas, you will not be going to space today.\n");
+  logpanic("alas, you will not be going to space today.");
   notcurses_stop_minimal(ret);
   fbuf_free(&ret->rstate.f);
   if(ret->tcache.ttyfd >= 0 && ret->tcache.tpreserved){
@@ -1365,7 +1365,7 @@ ncpile_drop(notcurses* nc, ncpile** pile){
   ncplane* p = (*pile)->top;
   while(p){
     ncplane* tmp = p->below;
-    logdebug("killing plane %p, next is %p\n", p, tmp);
+    logdebug("killing plane %p, next is %p", p, tmp);
     if(nc->stdplane != p){
       free_plane(p);
     }else{
@@ -1384,7 +1384,7 @@ ncpile_drop(notcurses* nc, ncpile** pile){
 
 // drop all piles and all planes, save the standard plane and its pile
 void notcurses_drop_planes(notcurses* nc){
-  logdebug("we have some planes\n");
+  logdebug("we have some planes");
   pthread_mutex_lock(&nc->pilelock);
   ncpile* p = ncplane_pile(nc->stdplane);
   ncpile* p0 = p;
@@ -1392,11 +1392,11 @@ void notcurses_drop_planes(notcurses* nc){
     ncpile_drop(nc, &p);
   }while(p0 != p);
   pthread_mutex_unlock(&nc->pilelock);
-  logdebug("all planes dropped\n");
+  logdebug("all planes dropped");
 }
 
 int notcurses_stop(notcurses* nc){
-  logdebug("stopping notcurses\n");
+  logdebug("stopping notcurses");
 //notcurses_debug(nc, stderr);
   int ret = 0;
   if(nc){
@@ -1412,9 +1412,7 @@ int notcurses_stop(notcurses* nc){
     }
     if(nc->stdplane){
       notcurses_drop_planes(nc);
-      logdebug("say goodbye to the standard plane\n");
       free_plane(nc->stdplane);
-      logdebug("get outta here\n");
     }
     if(nc->tcache.ttyfd >= 0){
       ret |= close(nc->tcache.ttyfd);
@@ -1738,11 +1736,11 @@ void scroll_down(ncplane* n){
 
 int ncplane_scrollup(ncplane* n, int r){
   if(!ncplane_scrolling_p(n)){
-    logerror("can't scroll %d on non-scrolling plane\n", r);
+    logerror("can't scroll %d on non-scrolling plane", r);
     return -1;
   }
   if(r < 0){
-    logerror("can't scroll %d lines\n", r);
+    logerror("can't scroll %d lines", r);
     return -1;
   }
   while(r-- > 0){
@@ -1756,11 +1754,11 @@ int ncplane_scrollup(ncplane* n, int r){
 // is fixed. Returns the number of scrolling events otherwise (might be 0).
 int ncplane_scrollup_child(ncplane* n, const ncplane* child){
   if(ncplane_parent_const(child) != n){
-    logerror("not a child of specified plane\n");
+    logerror("not a child of specified plane");
     return -1;
   }
   if(child->fixedbound){
-    logerror("child plane is fixed\n");
+    logerror("child plane is fixed");
     return -1;
   }
   int parend = ncplane_abs_y(n) + ncplane_dim_y(n) - 1; // where parent ends
@@ -1789,7 +1787,7 @@ static int
 ncplane_put(ncplane* n, int y, int x, const char* egc, int cols,
             uint16_t stylemask, uint64_t channels, int bytes){
   if(n->sprite){
-    logerror("can't write [%s] to sprixelated plane\n", egc);
+    logerror("can't write [%s] to sprixelated plane", egc);
     return -1;
   }
   // reject any control character for output other than newline (and then only
@@ -1798,11 +1796,11 @@ ncplane_put(ncplane* n, int y, int x, const char* egc, int cols,
     // if we're not scrolling, autogrow would be to the right (as opposed to
     // down), and thus it still wouldn't apply to the case of a newline.
     if(!n->scrolling){
-      logerror("rejecting newline on non-scrolling plane\n");
+      logerror("rejecting newline on non-scrolling plane");
       return -1;
     }
   }else if(is_control_egc((const unsigned char*)egc, bytes)){
-    logerror("rejecting %dB control character\n", bytes);
+    logerror("rejecting %dB control character", bytes);
     return -1;
   }
   // check *before ncplane_cursor_move_yx()* whether we're past the end of the
@@ -1829,7 +1827,7 @@ ncplane_put(ncplane* n, int y, int x, const char* egc, int cols,
     }else if(n->autogrow){
       ncplane_resize_simple(n, n->leny, n->lenx + cols);
     }else{
-      logerror("target x %d [%.*s] > length %d\n", n->x, bytes, egc, n->lenx);
+      logerror("target x %d [%.*s] > length %d", n->x, bytes, egc, n->lenx);
       return -1;
     }
   }
@@ -1893,7 +1891,7 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const nccell* c){
   // nccell_extended_gcluster(). so we must copy and free it.
   char* egc = nccell_strdup(n, c);
   if(egc == NULL){
-    logerror("couldn't duplicate cell\n");
+    logerror("couldn't duplicate cell");
     return -1;
   }
   int r = ncplane_put(n, y, x, egc, cols, c->stylemask, c->channels, strlen(egc));
@@ -2062,7 +2060,7 @@ int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_t s,
 int ncplane_hline_interp(ncplane* n, const nccell* c, unsigned len,
                          uint64_t c1, uint64_t c2){
   if(len <= 0){
-    logerror("passed invalid length %u\n", len);
+    logerror("passed invalid length %u", len);
     return -1;
   }
   unsigned ur, ug, ub;
@@ -2118,7 +2116,7 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, unsigned len,
 int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len,
                          uint64_t c1, uint64_t c2){
   if(len <= 0){
-    logerror("passed invalid length %u\n", len);
+    logerror("passed invalid length %u", len);
     return -1;
   }
   unsigned ur, ug, ub;
@@ -2185,18 +2183,18 @@ int ncplane_box(ncplane* n, const nccell* ul, const nccell* ur,
   ncplane_cursor_yx(n, &yoff, &xoff);
   // must be at least 2x2, with its upper-left corner at the current cursor
   if(ystop < yoff + 1){
-    logerror("ystop (%u) insufficient for yoff (%d)\n", ystop, yoff);
+    logerror("ystop (%u) insufficient for yoff (%d)", ystop, yoff);
     return -1;
   }
   if(xstop < xoff + 1){
-    logerror("xstop (%u) insufficient for xoff (%d)\n", xstop, xoff);
+    logerror("xstop (%u) insufficient for xoff (%d)", xstop, xoff);
     return -1;
   }
   unsigned ymax, xmax;
   ncplane_dim_yx(n, &ymax, &xmax);
   // must be within the ncplane
   if(xstop >= xmax || ystop >= ymax){
-    logerror("Boundary (%ux%u) beyond plane (%dx%d)\n", ystop, xstop, ymax, xmax);
+    logerror("boundary (%ux%u) beyond plane (%dx%d)", ystop, xstop, ymax, xmax);
     return -1;
   }
   unsigned edges;
@@ -2365,7 +2363,7 @@ void ncplane_yx(const ncplane* n, int* y, int* x){
 
 // special case of ncplane_erase_region()
 void ncplane_erase(ncplane* n){
-  loginfo("erasing %dx%d plane\n", n->leny, n->lenx);
+  loginfo("erasing %dx%d plane", n->leny, n->lenx);
   if(n->sprite){
     sprixel_hide(n->sprite);
     destroy_tam(n);
@@ -2393,11 +2391,11 @@ int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen)
     xstart = n->x;
   }
   if(ystart < 0 || xstart < 0){
-    logerror("Illegal start of erase (%d, %d)\n", ystart, xstart);
+    logerror("illegal start of erase (%d, %d)", ystart, xstart);
     return -1;
   }
   if(ystart >= (int)ncplane_dim_y(n) || xstart >= (int)ncplane_dim_x(n)){
-    logerror("Illegal start of erase (%d, %d)\n", ystart, xstart);
+    logerror("illegal start of erase (%d, %d)", ystart, xstart);
     return -1;
   }
   if(xlen < 0){
@@ -2436,7 +2434,7 @@ int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen)
     n->x = tmpx;
     return 0;
   }
-  loginfo("erasing %d/%d - %d/%d\n", ystart, xstart, ystart + ylen, xstart + xlen);
+  loginfo("erasing %d/%d - %d/%d", ystart, xstart, ystart + ylen, xstart + xlen);
   for(int y = ystart ; y < ystart + ylen ; ++y){
     for(int x = xstart ; x < xstart + xlen ; ++x){
       nccell_release(n, &n->fb[nfbcellidx(n, y, x)]);
@@ -2596,7 +2594,7 @@ int ncplane_resize_placewithin(ncplane* n){
   int ret = 0;
   if(absy + ncplane_dim_y(n) > ncplane_dim_y(n->boundto)){
     const int dy = (absy + ncplane_dim_y(n)) - ncplane_dim_y(n->boundto);
-    logdebug("moving up %d\n", dy);
+    logdebug("moving up %d", dy);
     if(ncplane_move_rel(n, -dy, 0)){
       ret = -1;
     }
@@ -2604,7 +2602,7 @@ int ncplane_resize_placewithin(ncplane* n){
   }
   if(absx + ncplane_dim_x(n) > ncplane_dim_x(n->boundto)){
     const int dx = ncplane_dim_x(n->boundto) - (absx + ncplane_dim_x(n));
-    logdebug("moving left %d\n", dx);
+    logdebug("moving left %d", dx);
     if(ncplane_move_rel(n, 0, dx)){
       ret = -1;
     }
@@ -2613,7 +2611,7 @@ int ncplane_resize_placewithin(ncplane* n){
   // this will prefer upper-left material if the child plane is larger than
   // the parent. we might want a smarter rule, one based on origin?
   if(absy < 0){
-    logdebug("moving down %d\n", -absy);
+    logdebug("moving down %d", -absy);
     // we're at least partially above our parent
     if(ncplane_move_rel(n, -absy, 0)){
       ret = -1;
@@ -2621,7 +2619,7 @@ int ncplane_resize_placewithin(ncplane* n){
     absy = ncplane_abs_y(n);
   }
   if(absx < 0){
-    logdebug("moving right %d\n", -absx);
+    logdebug("moving right %d", -absx);
     // we're at least partially to the left of our parent
     if(ncplane_move_rel(n, 0, -absx)){
       ret = -1;
@@ -2657,7 +2655,7 @@ int ncplane_resize_marginalized(ncplane* n){
   }
   int targy = maxy - n->margin_b;
   int targx = maxx - n->margin_b;
-  loginfo("marg %d/%d, pdim %d/%d, move %d/%d\n", n->margin_b, n->margin_r, maxy, maxx, targy, targx);
+  loginfo("marg %d/%d, pdim %d/%d, move %d/%d", n->margin_b, n->margin_r, maxy, maxx, targy, targx);
   return ncplane_move_yx(n, targy, targx);
 }
 
@@ -2675,11 +2673,11 @@ int ncplane_resize_maximize(ncplane* n){
 int ncplane_resize_realign(ncplane* n){
   const ncplane* parent = ncplane_parent_const(n);
   if(parent == n){
-    logerror("Can't realign a root plane\n");
+    logerror("can't realign a root plane");
     return 0;
   }
   if(n->halign == NCALIGN_UNALIGNED && n->valign == NCALIGN_UNALIGNED){
-    logerror("Passed a non-aligned plane\n");
+    logerror("passed a non-aligned plane");
     return -1;
   }
   int xpos = ncplane_x(n);
@@ -2702,11 +2700,11 @@ int ncplane_resize_realign(ncplane* n){
 ncplane* ncplane_reparent(ncplane* n, ncplane* newparent){
   const notcurses* nc = ncplane_notcurses_const(n);
   if(n == nc->stdplane){
-    logerror("won't reparent standard plane\n");
+    logerror("won't reparent standard plane");
     return NULL; // can't reparent standard plane
   }
   if(n->boundto == newparent){
-    loginfo("won't reparent plane to itself\n");
+    loginfo("won't reparent plane to itself");
     return n; // don't return error, just a no-op
   }
 //notcurses_debug(ncplane_notcurses(n), stderr);
@@ -2854,7 +2852,7 @@ ncplane* ncplane_reparent_family(ncplane* n, ncplane* newparent){
   const unsigned ocellpxx = ncplane_pile(n)->cellpxx;
   n->boundto = newparent;
   if(n == n->boundto){ // we're a new root plane
-    logdebug("reparenting new root plane %p\n", n);
+    logdebug("reparenting new root plane %p", n);
     unsplice_zaxis_recursive(n);
     n->bnext = NULL;
     n->bprev = NULL;
@@ -2913,7 +2911,7 @@ bool ncplane_scrolling_p(const ncplane* n){
 
 bool ncplane_set_autogrow(ncplane* n, unsigned growp){
   if(n == notcurses_stdplane_const(ncplane_notcurses_const(n))){
-    logerror("can't set the standard plane autogrow\n");
+    logerror("can't set the standard plane autogrow");
     return false;
   }
   bool old = n->autogrow;
@@ -2932,11 +2930,11 @@ lex_ulong(const char* op, unsigned* i, char** endptr){
   errno = 0;
   long l = strtol(op, endptr, 10);
   if(l < 0 || (l == LONG_MAX && errno == ERANGE) || (l > INT_MAX)){
-    fprintf(stderr, "Invalid margin: %s\n", op);
+    fprintf(stderr, "invalid margin: %s", op);
     return -1;
   }
   if((**endptr != ',' && **endptr) || *endptr == op){
-    fprintf(stderr, "Invalid margin: %s\n", op);
+    fprintf(stderr, "invalid margin: %s", op);
     return -1;
   }
   *i = l;
@@ -3047,16 +3045,16 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
     return NULL;
   }
   if(blit == NCBLIT_PIXEL){ // FIXME extend this to support sprixels
-    logerror("pixel blitter %d not yet supported\n", blit);
+    logerror("pixel blitter %d not yet supported", blit);
     return NULL;
   }
   if(blit == NCBLIT_DEFAULT){
-    logerror("must specify exact blitter, not NCBLIT_DEFAULT\n");
+    logerror("must specify exact blitter, not NCBLIT_DEFAULT");
     return NULL;
   }
   const struct blitset* bset = lookup_blitset(&ncur->tcache, blit, false);
   if(bset == NULL){
-    logerror("blitter %d invalid in current environment\n", blit);
+    logerror("blitter %d invalid in current environment", blit);
     return NULL;
   }
 //fprintf(stderr, "ALLOCATING %u %d %d %p\n", 4u * lenx * leny * 2, leny, lenx, bset);
@@ -3198,7 +3196,7 @@ int ncplane_putwstr_stained(ncplane* n, const wchar_t* gclustarr){
   const wchar_t** wset = &gclustarr;
   size_t mbytes = wcsrtombs(NULL, wset, 0, &ps);
   if(mbytes == (size_t)-1){
-    logerror("error converting wide string\n");
+    logerror("error converting wide string");
     return -1;
   }
   ++mbytes;
diff --git a/src/lib/plot.c b/src/lib/plot.c
index 15c5e1678..99954d017 100644
--- a/src/lib/plot.c
+++ b/src/lib/plot.c
@@ -441,23 +441,23 @@ create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, const T mi
     opts = &zeroed; \
   } \
   if(opts->flags >= (NCPLOT_OPTION_PRINTSAMPLE << 1u)){ \
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags); \
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags); \
   } \
   /* if miny == maxy (enabling domain detection), they both must be equal to 0 */ \
   if(miny == maxy && miny){ \
     return NULL; \
   } \
   if(opts->rangex < 0){ \
-    logerror("error: supplied negative independent range %d\n", opts->rangex); \
+    logerror("error: supplied negative independent range %d", opts->rangex); \
     return NULL; \
   } \
   if(maxy < miny){ \
-    logerror("error: supplied maxy < miny\n"); \
+    logerror("error: supplied maxy < miny"); \
     return NULL; \
   } \
   /* DETECTMAXONLY can't be used without domain detection */ \
   if(opts->flags & NCPLOT_OPTION_DETECTMAXONLY && (miny != maxy)){ \
-    logerror("Supplied DETECTMAXONLY without domain detection"); \
+    logerror("supplied DETECTMAXONLY without domain detection"); \
     return NULL; \
   } \
   const notcurses* notc = ncplane_notcurses(n); \
diff --git a/src/lib/progbar.c b/src/lib/progbar.c
index b225d6ee9..7a19cf0a1 100644
--- a/src/lib/progbar.c
+++ b/src/lib/progbar.c
@@ -8,7 +8,7 @@ ncprogbar* ncprogbar_create(ncplane* n, const ncprogbar_options* opts){
     opts = &default_opts;
   }
   if(opts->flags > (NCPROGBAR_OPTION_RETROGRADE << 1u)){
-    logwarn("Invalid flags %016" PRIx64 "\n", opts->flags);
+    logwarn("invalid flags %016" PRIx64, opts->flags);
   }
   ncprogbar* ret = malloc(sizeof(*ret));
   if(ret == NULL){
@@ -176,7 +176,7 @@ progbar_redraw(ncprogbar* n){
 int ncprogbar_set_progress(ncprogbar* n, double p){
 //fprintf(stderr, "PROGRESS: %g\n", p);
   if(p < 0 || p > 1){
-    logerror("Invalid progress %g\n", p);
+    logerror("invalid progress %g", p);
     return -1;
   }
   n->progress = p;
diff --git a/src/lib/reader.c b/src/lib/reader.c
index f3b2a4d2b..f6ba120f3 100644
--- a/src/lib/reader.c
+++ b/src/lib/reader.c
@@ -29,7 +29,7 @@ ncreader* ncreader_create(ncplane* n, const ncreader_options* opts){
     opts = &zeroed;
   }
   if(opts->flags > NCREADER_OPTION_CURSOR){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
   ncreader* nr = malloc(sizeof(*nr));
   if(nr == NULL){
@@ -216,7 +216,7 @@ int ncreader_move_down(ncreader* n){
 int ncreader_write_egc(ncreader* n, const char* egc){
   const int cols = ncstrwidth(egc, NULL, NULL);
   if(cols < 0){
-    logerror("Fed illegal UTF-8 [%s]\n", egc);
+    logerror("fed illegal UTF-8 [%s]", egc);
     return -1;
   }
   if(n->textarea->x >= n->textarea->lenx - cols){
diff --git a/src/lib/reel.c b/src/lib/reel.c
index ce83c18cd..ec6fb84b7 100644
--- a/src/lib/reel.c
+++ b/src/lib/reel.c
@@ -370,7 +370,7 @@ ncreel_draw_tablet(const ncreel* nr, nctablet* t, int frontiertop,
     int ll = t->cbfxn(t, direction == DIRECTION_DOWN);
 //fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", t, ll, cby, cbleny, leny, direction);
     if(ll > cbleny){
-      logwarn("Tablet callback returned %d lines, %d allowed\n", ll, cbleny);
+      logwarn("tablet callback returned %d lines, %d allowed", ll, cbleny);
       ll = cbleny;
     }
     if(ll != cbleny){
@@ -722,7 +722,7 @@ int ncreel_redraw(ncreel* nr){
   if(focused){
 //fprintf(stderr, "drawing focused tablet %p dir: %d fulcrum: %d!\n", focused, nr->direction, fulcrum);
     if(ncreel_draw_tablet(nr, focused, fulcrum, fulcrum, DIRECTION_DOWN)){
-      logerror("Error drawing tablet\n");
+      logerror("error drawing tablet");
       return -1;
     }
 //fprintf(stderr, "drew focused tablet %p -> %p lastdir: %d!\n", focused, focused->p, nr->direction);
@@ -734,25 +734,25 @@ int ncreel_redraw(ncreel* nr){
     if(nr->direction == LASTDIRECTION_DOWN){
       otherend = draw_previous_tablets(nr, otherend, &frontiertop, frontierbottom);
       if(otherend == NULL){
-        logerror("Error drawing higher tablets\n");
+        logerror("error drawing higher tablets");
         return -1;
       }
       otherend = draw_following_tablets(nr, otherend, frontiertop, &frontierbottom);
     }else{ // DIRECTION_UP
       otherend = draw_previous_tablets(nr, otherend, &frontiertop, frontierbottom);
       if(otherend == NULL){
-        logerror("Error drawing higher tablets\n");
+        logerror("error drawing higher tablets");
         return -1;
       }
       otherend = draw_following_tablets(nr, otherend, frontiertop, &frontierbottom);
     }
     if(otherend == NULL){
-      logerror("Error drawing following tablets\n");
+      logerror("error drawing following tablets");
       return -1;
     }
 //notcurses_debug(ncplane_notcurses(nr->p), stderr);
     if(tighten_reel(nr)){
-      logerror("Error tightening reel\n");
+      logerror("error tightening reel");
       return -1;
     }
 //notcurses_debug(ncplane_notcurses(nr->p), stderr);
@@ -760,7 +760,7 @@ int ncreel_redraw(ncreel* nr){
   nr->vft = nr->tablets; // update the visually-focused tablet pointer
 //fprintf(stderr, "DONE ARRANGING\n");
   if(draw_ncreel_borders(nr)){
-    logerror("Error drawing reel borders\n");
+    logerror("error drawing reel borders");
     return -1; // enforces specified dimensional minima
   }
   return 0;
@@ -772,11 +772,11 @@ validate_ncreel_opts(ncplane* n, const ncreel_options* ropts){
     return false;
   }
   if(ropts->flags >= (NCREEL_OPTION_CIRCULAR << 1u)){
-    logwarn("Provided unsupported flags 0x%016" PRIx64 "\n", ropts->flags);
+    logwarn("provided unsupported flags 0x%016" PRIx64, ropts->flags);
   }
   if(ropts->flags & NCREEL_OPTION_CIRCULAR){
     if(!(ropts->flags & NCREEL_OPTION_INFINITESCROLL)){
-      logerror("Can't set circular without infinitescroll\n");
+      logerror("can't set circular without infinitescroll");
       return false; // can't set circular without infinitescroll
     }
   }
@@ -786,11 +786,11 @@ validate_ncreel_opts(ncplane* n, const ncreel_options* ropts){
                             NCBOXMASK_TOP |
                             NCBOXMASK_BOTTOM;
   if(ropts->bordermask > fullmask){
-    logerror("Bad bordermask: 0x%016x\n", ropts->bordermask);
+    logerror("bad bordermask: 0x%016x", ropts->bordermask);
     return false;
   }
   if(ropts->tabletmask > fullmask){
-    logerror("Bad tabletmask: 0x%016x\n", ropts->bordermask);
+    logerror("bad tabletmask: 0x%016x", ropts->bordermask);
     return false;
   }
   return true;
@@ -840,7 +840,7 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
   nctablet* t;
   if(after && before){
     if(after->next != before || before->prev != after){
-      logerror("bad before (%p) / after (%p) spec\n", before, after);
+      logerror("bad before (%p) / after (%p) spec", before, after);
       return NULL;
     }
   }else if(!after && !before){
diff --git a/src/lib/render.c b/src/lib/render.c
index d97fc8e2f..fa00502c2 100644
--- a/src/lib/render.c
+++ b/src/lib/render.c
@@ -132,7 +132,7 @@ void nccell_release(ncplane* n, nccell* c){
 // Duplicate one cell onto another when they share a plane. Convenience wrapper.
 int nccell_duplicate(ncplane* n, nccell* targ, const nccell* c){
   if(cell_duplicate_far(&n->pool, targ, n, c) < 0){
-    logerror("Failed duplicating cell\n");
+    logerror("failed duplicating cell");
     return -1;
   }
   return 0;
@@ -517,66 +517,66 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst,
 //fprintf(stderr, "Merging down %d/%d @ %d/%d to %d/%d\n", leny, lenx, begsrcy, begsrcx, dsty, dstx);
   if(dsty < 0){
     if(dsty != -1){
-      logerror("invalid dsty %d\n", dsty);
+      logerror("invalid dsty %d", dsty);
       return -1;
     }
     dsty = dst->y;
   }
   if(dstx < 0){
     if(dstx != -1){
-      logerror("invalid dstx %d\n", dstx);
+      logerror("invalid dstx %d", dstx);
       return -1;
     }
     dstx = dst->x;
   }
   if((unsigned)dsty >= dst->leny || (unsigned)dstx >= dst->lenx){
-    logerror("dest origin %u/%u ≥ dest dimensions %d/%d\n",
+    logerror("dest origin %u/%u ≥ dest dimensions %d/%d",
              dsty, dstx, dst->leny, dst->lenx);
     return -1;
   }
   if(begsrcy < 0){
     if(begsrcy != -1){
-      logerror("invalid begsrcy %d\n", begsrcy);
+      logerror("invalid begsrcy %d", begsrcy);
       return -1;
     }
     begsrcy = src->y;
   }
   if(begsrcx < 0){
     if(begsrcx != -1){
-      logerror("invalid begsrcx %d\n", begsrcx);
+      logerror("invalid begsrcx %d", begsrcx);
       return -1;
     }
     begsrcx = src->x;
   }
   if((unsigned)begsrcy >= src->leny || (unsigned)begsrcx >= src->lenx){
-    logerror("source origin %u/%u ≥ source dimensions %d/%d\n",
+    logerror("source origin %u/%u ≥ source dimensions %d/%d",
              begsrcy, begsrcx, src->leny, src->lenx);
     return -1;
   }
   if(leny == 0){
     if((leny = src->leny - begsrcy) == 0){
-      logerror("source area was zero height\n");
+      logerror("source area was zero height");
       return -1;
     }
   }
   if(lenx == 0){
     if((lenx = src->lenx - begsrcx) == 0){
-      logerror("source area was zero width\n");
+      logerror("source area was zero width");
       return -1;
     }
   }
   if(dst->leny - leny < (unsigned)dsty || dst->lenx - lenx < (unsigned)dstx){
-    logerror("dest len %u/%u ≥ dest dimensions %d/%d\n",
+    logerror("dest len %u/%u ≥ dest dimensions %d/%d",
              leny, lenx, dst->leny, dst->lenx);
     return -1;
   }
   if(src->leny - leny < (unsigned)begsrcy || src->lenx - lenx < (unsigned)begsrcx){
-    logerror("source len %u/%u ≥ source dimensions %d/%d\n",
+    logerror("source len %u/%u ≥ source dimensions %d/%d",
              leny, lenx, src->leny, src->lenx);
     return -1;
   }
   if(src->sprite || dst->sprite){
-    logerror("can't merge sprixel planes\n");
+    logerror("can't merge sprixel planes");
     return -1;
   }
   const int totalcells = dst->leny * dst->lenx;
@@ -584,7 +584,7 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst,
   const size_t crenderlen = sizeof(struct crender) * totalcells;
   struct crender* rvec = malloc(crenderlen);
   if(!rendfb || !rvec){
-    logerror("error allocating render state for %ux%u\n", leny, lenx);
+    logerror("error allocating render state for %ux%u", leny, lenx);
     free(rendfb);
     free(rvec);
     return -1;
@@ -889,7 +889,7 @@ clean_sprixels(notcurses* nc, ncpile* p, fbuf* f, int scrolls){
   sprixel** parent = &p->sprixelcache;
   int64_t bytesemitted = 0;
   while( (s = *parent) ){
-    loginfo("Phase 1 sprixel %u state %d loc %d/%d\n", s->id,
+    loginfo("phase 1 sprixel %u state %d loc %d/%d", s->id,
             s->invalidated, s->n ? s->n->absy : -1, s->n ? s->n->absx : -1);
     if(s->invalidated == SPRIXEL_QUIESCENT){
       if(p != nc->last_pile){
@@ -985,7 +985,7 @@ rasterize_scrolls(const ncpile* p, fbuf* f){
   if(scrolls == 0){
     return 0;
   }
-  logdebug("order-%d scroll\n", scrolls);
+  logdebug("order-%d scroll", scrolls);
   /*if(p->nc->rstate.logendy >= 0){
     p->nc->rstate.logendy -= scrolls;
     if(p->nc->rstate.logendy < 0){
@@ -1270,7 +1270,7 @@ rasterize_core(notcurses* nc, const ncpile* p, fbuf* f, unsigned phase){
 // desired; in this case, a SUM footer is present at the end of the buffer.
 static int
 notcurses_rasterize_inner(notcurses* nc, ncpile* p, fbuf* f, unsigned* asu){
-  logdebug("pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->margin_t, p->dimx + nc->margin_l);
+  logdebug("pile %p ymax: %d xmax: %d", p, p->dimy + nc->margin_t, p->dimx + nc->margin_l);
   // don't write a clearscreen. we only update things that have been changed.
   // we explicitly move the cursor at the beginning of each output line, so no
   // need to home it expliticly.
@@ -1280,16 +1280,16 @@ notcurses_rasterize_inner(notcurses* nc, ncpile* p, fbuf* f, unsigned* asu){
   }
   int scrolls = p->scrolls;
   p->scrolls = 0;
-  logdebug("Sprixel phase 1\n");
+  logdebug("sprixel phase 1");
   int64_t sprixelbytes = clean_sprixels(nc, p, f, scrolls);
   if(sprixelbytes < 0){
     return -1;
   }
-  logdebug("Glyph phase 1\n");
+  logdebug("glyph phase 1");
   if(rasterize_core(nc, p, f, 0)){
     return -1;
   }
-  logdebug("Sprixel phase 2\n");
+  logdebug("sprixel phase 2");
   int64_t rasprixelbytes = rasterize_sprixels(nc, p, f);
   if(rasprixelbytes < 0){
     return -1;
@@ -1298,7 +1298,7 @@ notcurses_rasterize_inner(notcurses* nc, ncpile* p, fbuf* f, unsigned* asu){
   pthread_mutex_lock(&nc->stats.lock);
     nc->stats.s.sprixelbytes += sprixelbytes;
   pthread_mutex_unlock(&nc->stats.lock);
-  logdebug("Glyph phase 2\n");
+  logdebug("glyph phase 2");
   if(rasterize_core(nc, p, f, 1)){
     return -1;
   }
@@ -1550,7 +1550,7 @@ engorge_crender_vector(ncpile* p){
   const size_t crenderlen = p->dimy * p->dimx; // desired size
 //fprintf(stderr, "crlen: %d y: %d x:%d\n", crenderlen, dimy, dimx);
   if(crenderlen != p->crenderlen){
-    loginfo("resizing rvec (%" PRIuPTR ") for %p to %" PRIuPTR "\n",
+    loginfo("resizing rvec (%" PRIuPTR ") for %p to %" PRIuPTR,
             p->crenderlen, p, crenderlen);
     struct crender* tmp = realloc(p->crender, sizeof(*tmp) * crenderlen);
     if(tmp == NULL){
@@ -1621,15 +1621,15 @@ pool_egc_copy(const egcpool* e, const nccell* c){
 
 char* notcurses_at_yx(notcurses* nc, unsigned yoff, unsigned xoff, uint16_t* stylemask, uint64_t* channels){
   if(nc->lastframe == NULL){
-    logerror("haven't yet rendered\n");
+    logerror("haven't yet rendered");
     return NULL;
   }
   if(yoff >= nc->lfdimy){
-    logerror("invalid coordinates: %u/%u\n", yoff, xoff);
+    logerror("invalid coordinates: %u/%u", yoff, xoff);
     return NULL;
   }
   if(xoff >= nc->lfdimx){
-    logerror("invalid coordinates: %u/%u\n", yoff, xoff);
+    logerror("invalid coordinates: %u/%u", yoff, xoff);
     return NULL;
   }
   const nccell* srccell = &nc->lastframe[yoff * nc->lfdimx + xoff];
@@ -1709,7 +1709,7 @@ int ncdirect_set_fg_rgb(ncdirect* nc, unsigned rgb){
 int notcurses_default_foreground(const struct notcurses* nc, uint32_t* fg){
   const tinfo* ti = &nc->tcache;
   if(ti->fg_default & 0x80000000){
-    logerror("default foreground could not be determined\n");
+    logerror("default foreground could not be determined");
     return -1;
   }
   *fg = ti->fg_default & NC_BG_RGB_MASK;
@@ -1719,7 +1719,7 @@ int notcurses_default_foreground(const struct notcurses* nc, uint32_t* fg){
 int notcurses_default_background(const struct notcurses* nc, uint32_t* bg){
   const tinfo* ti = &nc->tcache;
   if(ti->bg_collides_default & 0x80000000){
-    logerror("default background could not be determined\n");
+    logerror("default background could not be determined");
     return -1;
   }
   *bg = ti->bg_collides_default & NC_BG_RGB_MASK;
@@ -1734,7 +1734,7 @@ int notcurses_cursor_yx(const notcurses* nc, int* y, int* x){
 
 int notcurses_cursor_enable(notcurses* nc, int y, int x){
   if(y < 0 || x < 0){
-    logerror("Illegal cursor placement: %d, %d\n", y, x);
+    logerror("illegal cursor placement: %d, %d", y, x);
     return -1;
   }
   // if we're already at the demanded location, we must already be visible, and
@@ -1768,7 +1768,7 @@ int notcurses_cursor_enable(notcurses* nc, int y, int x){
 
 int notcurses_cursor_disable(notcurses* nc){
   if(nc->cursorx < 0 || nc->cursory < 0){
-    logerror("Cursor is not enabled\n");
+    logerror("cursor is not enabled");
     return -1;
   }
   const char* cinvis = get_escape(&nc->tcache, ESCAPE_CIVIS);
diff --git a/src/lib/selector.c b/src/lib/selector.c
index 2b9175069..824340547 100644
--- a/src/lib/selector.c
+++ b/src/lib/selector.c
@@ -279,7 +279,7 @@ void ncselector_destroy(ncselector* n, char** item){
 
 ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
   if(n == notcurses_stdplane(ncplane_notcurses(n))){
-    logerror("won't use the standard plane\n"); // would fail later on resize
+    logerror("won't use the standard plane"); // would fail later on resize
     return NULL;
   }
   ncselector_options zeroed = {0};
@@ -288,7 +288,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
   }
   unsigned itemcount = 0;
   if(opts->flags > 0){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
   if(opts->items){
     for(const struct ncselector_item* i = opts->items ; i->option ; ++i){
@@ -301,7 +301,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
   }
   memset(ns, 0, sizeof(*ns));
   if(opts->defidx && opts->defidx >= itemcount){
-    logerror("default index %u too large (%u items)\n", opts->defidx, itemcount);
+    logerror("default index %u too large (%u items)", opts->defidx, itemcount);
     goto freeitems;
   }
   ns->title = opts->title ? strdup(opts->title) : NULL;
@@ -884,7 +884,7 @@ ncmultiselector_dim_yx(const ncmultiselector* n, unsigned* ncdimy, unsigned* ncd
 
 ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_options* opts){
   if(n == notcurses_stdplane(ncplane_notcurses(n))){
-    logerror("won't use the standard plane\n"); // would fail later on resize
+    logerror("won't use the standard plane"); // would fail later on resize
     return NULL;
   }
   ncmultiselector_options zeroed = {0};
@@ -892,7 +892,7 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
     opts = &zeroed;
   }
   if(opts->flags > 0){
-    logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags %016" PRIx64, opts->flags);
   }
   unsigned itemcount = 0;
   if(opts->items){
diff --git a/src/lib/sixel.c b/src/lib/sixel.c
index 585dce306..d517c5c01 100644
--- a/src/lib/sixel.c
+++ b/src/lib/sixel.c
@@ -963,7 +963,7 @@ int sixel_blit(ncplane* n, int linesize, const void* data, int leny, int lenx,
 // (though we'll still need to if the new sprixcell not opaque, and the
 // old and new sprixcell are different in any transparent pixel).
 int sixel_scrub(const ncpile* p, sprixel* s){
-  loginfo("%d state %d at %d/%d (%d/%d)\n", s->id, s->invalidated, s->movedfromy, s->movedfromx, s->dimy, s->dimx);
+  loginfo("%d state %d at %d/%d (%d/%d)", s->id, s->invalidated, s->movedfromy, s->movedfromx, s->dimy, s->dimx);
   int starty = s->movedfromy;
   int startx = s->movedfromx;
   for(int yy = starty ; yy < starty + (int)s->dimy && yy < (int)p->dimy ; ++yy){
diff --git a/src/lib/sprite.c b/src/lib/sprite.c
index 64760c65d..0320c85b4 100644
--- a/src/lib/sprite.c
+++ b/src/lib/sprite.c
@@ -5,7 +5,7 @@
 static atomic_uint_fast32_t sprixelid_nonce;
 
 void sprixel_debug(const sprixel* s, FILE* out){
-  fprintf(out, "Sprixel %d (%p) %" PRIu64 "B %dx%d (%dx%d) @%d/%d state: %d\n",
+  fprintf(out, "sprixel %d (%p) %" PRIu64 "B %dx%d (%dx%d) @%d/%d state: %d\n",
           s->id, s, s->glyph.used, s->dimy, s->dimx, s->pixy, s->pixx,
           s->n ? s->n->absy : 0, s->n ? s->n->absx : 0,
           s->invalidated);
@@ -37,7 +37,7 @@ void sprixel_debug(const sprixel* s, FILE* out){
 // doesn't splice us out of any lists, just frees
 void sprixel_free(sprixel* s){
   if(s){
-    loginfo("Destroying sprixel %u\n", s->id);
+    loginfo("destroying sprixel %u", s->id);
     if(s->n){
       s->n->sprite = NULL;
     }
@@ -87,7 +87,7 @@ void sprixel_hide(sprixel* s){
   }
   // otherwise, it'll be killed in the next rendering cycle.
   if(s->invalidated != SPRIXEL_HIDE){
-    loginfo("Marking sprixel %u hidden\n", s->id);
+    loginfo("marking sprixel %u hidden", s->id);
     s->invalidated = SPRIXEL_HIDE;
     s->movedfromy = ncplane_abs_y(s->n);
     s->movedfromx = ncplane_abs_x(s->n);
@@ -191,7 +191,7 @@ int sprite_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
 //fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell);
     return 0;
   }
-  logdebug("wiping %p %d %d/%d\n", s->n->tam, idx, ycell, xcell);
+  logdebug("wiping %p %d %d/%d", s->n->tam, idx, ycell, xcell);
   int r = nc->tcache.pixel_wipe(s, ycell, xcell);
 //fprintf(stderr, "WIPED %d %d/%d ret=%d\n", s->id, ycell, xcell, r);
   // mark the cell as annihilated whether we actually scrubbed it or not,
@@ -224,7 +224,7 @@ int sprite_init(const tinfo* t, int fd){
 
 int sprixel_rescale(sprixel* spx, unsigned ncellpxy, unsigned ncellpxx){
   assert(spx->n);
-  loginfo("rescaling -> %ux%u\n", ncellpxy, ncellpxx);
+  loginfo("rescaling -> %ux%u", ncellpxy, ncellpxx);
   // FIXME need adjust for sixel (scale_height)
   int nrows = (spx->pixy + (ncellpxy - 1)) / ncellpxy;
   int ncols = (spx->pixx + (ncellpxx - 1)) / ncellpxx;
diff --git a/src/lib/tabbed.c b/src/lib/tabbed.c
index a38552eef..62271e4fe 100644
--- a/src/lib/tabbed.c
+++ b/src/lib/tabbed.c
@@ -93,10 +93,10 @@ void nctabbed_ensure_selected_header_visible(nctabbed* nt){
 static bool
 nctabbed_validate_opts(const nctabbed_options* opts){
   if(opts->flags > NCTABBED_OPTION_BOTTOM){
-    logwarn("Provided unsupported flags 0x%016" PRIx64 "\n", opts->flags);
+    logwarn("provided unsupported flags 0x%016" PRIx64, opts->flags);
   }
   if(opts->sepchan && !opts->separator){
-    logwarn("Provided non-zero separator channel when separator is NULL")
+    logwarn("provided non-zero separator channel when separator is NULL")
   }
   return true;
 }
@@ -235,7 +235,7 @@ nctab* nctabbed_add(nctabbed* nt, nctab* after, nctab* before, tabcb cb,
   nctab* t;
   if(after && before){
     if(after->next != before || before->prev != after){
-      logerror("bad before (%p) / after (%p) spec\n", before, after);
+      logerror("bad before (%p) / after (%p) spec", before, after);
       return NULL;
     }
   }else if(!after && !before){
@@ -305,11 +305,11 @@ int nctabbed_del(nctabbed* nt, nctab* t){
 int nctab_move(nctabbed* nt __attribute__ ((unused)), nctab* t, nctab* after, nctab* before){
   if(after && before){
     if(after->prev != before || before->next != after){
-      logerror("bad before (%p) / after (%p) spec\n", before, after);
+      logerror("bad before (%p) / after (%p) spec", before, after);
       return -1;
     }
   }else if(!after && !before){
-    logerror("bad before (%p) / after (%p) spec\n", before, after);
+    logerror("bad before (%p) / after (%p) spec", before, after);
     return -1;
   }
   // bad things would happen
diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c
index 31cd4a0d4..a1f7a2eb1 100644
--- a/src/lib/termdesc.c
+++ b/src/lib/termdesc.c
@@ -39,7 +39,7 @@ static void
 get_default_geometry(tinfo* ti){
   ti->default_rows = get_default_dimension("LINES", "lines", 24);
   ti->default_cols = get_default_dimension("COLUMNS", "cols", 80);
-  loginfo("default geometry: %d row%s, %d column%s\n",
+  loginfo("default geometry: %d row%s, %d column%s",
           ti->default_rows, ti->default_rows != 1 ? "s" : "",
           ti->default_cols, ti->default_cols != 1 ? "s" : "");
   ti->dimy = ti->default_rows;
@@ -593,7 +593,7 @@ send_initial_queries(int fd, unsigned minimal, unsigned noaltscreen,
     }
   }
   size_t len = strlen(queries);
-  loginfo("sending %lluB\n", (unsigned long long)len);
+  loginfo("sending %lluB", (unsigned long long)len);
   if(blocking_write(fd, queries, len)){
     return -1;
   }
@@ -1069,10 +1069,10 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
   ti->qterm = macos_early_matches();
 #elif defined(__MINGW32__)
   if(termtype){
-    logwarn("termtype (%s) ignored on windows\n", termtype);
+    logwarn("termtype (%s) ignored on windows", termtype);
   }
   if(prepare_windows_terminal(ti, &tablelen, &tableused)){
-    logpanic("failed opening Windows ConPTY\n");
+    logpanic("failed opening Windows ConPTY");
     return -1;
   }
 #else
@@ -1091,7 +1091,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
       return -1;
     }
     if(tcgetattr(ti->ttyfd, ti->tpreserved)){
-      logpanic("Couldn't preserve terminal state for %d (%s)\n", ti->ttyfd, strerror(errno));
+      logpanic("couldn't preserve terminal state for %d (%s)", ti->ttyfd, strerror(errno));
       free(ti->tpreserved);
       return -1;
     }
@@ -1113,7 +1113,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
   // machines, but they'll use the terminfo installed thereon (putty, etc.).
   int termerr;
   if(setupterm(termtype, ti->ttyfd, &termerr)){
-    logpanic("Terminfo error %d for [%s] (see terminfo(3ncurses))\n",
+    logpanic("terminfo error %d for [%s] (see terminfo(3ncurses))",
              termerr, termtype ? termtype : "");
     goto err;
   }
@@ -1189,7 +1189,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
   }
   // verify that the terminal provides cursor addressing (absolute movement)
   if(ti->escindices[ESCAPE_CUP] == 0){
-    logpanic("Required terminfo capability 'cup' not defined\n");
+    logpanic("required terminfo capability 'cup' not defined");
     goto err;
   }
   if(ti->ttyfd >= 0){
@@ -1197,7 +1197,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
     const char* smkx = get_escape(ti, ESCAPE_SMKX);
     if(smkx){
       if(tty_emit(tiparm(smkx), ti->ttyfd) < 0){
-        logpanic("Error enabling keypad transmit mode\n");
+        logpanic("error enabling keypad transmit mode");
         goto err;
       }
     }
@@ -1225,7 +1225,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
       // if we're not using the standard smcup, our initial hardcoded use of it
       // presumably had no effect; warn the user.
       if(strcmp(smcup, SMCUP)){
-        logwarn("warning: non-standard smcup!\n");
+        logwarn("warning: non-standard smcup!");
       }
     }
   }else{
@@ -1411,18 +1411,18 @@ char* termdesc_longterm(const tinfo* ti){
 int locate_cursor(tinfo* ti, unsigned* cursor_y, unsigned* cursor_x){
   const char* u7 = get_escape(ti, ESCAPE_U7);
   if(u7 == NULL){
-    logwarn("No support in terminfo\n");
+    logwarn("no support in terminfo");
     return -1;
   }
   if(ti->ttyfd < 0){
-    logwarn("No valid path for cursor report\n");
+    logwarn("no valid path for cursor report");
     return -1;
   }
   int fd = ti->ttyfd;
   if(get_cursor_location(ti->ictx, u7, cursor_y, cursor_x)){
     return -1;
   }
-  loginfo("got a report from %d %d/%d\n", fd, *cursor_y, *cursor_x);
+  loginfo("got a report from %d %d/%d", fd, *cursor_y, *cursor_x);
   return 0;
 }
 
@@ -1430,11 +1430,11 @@ int tiocgwinsz(int fd, struct winsize* ws){
 #ifndef __MINGW32__
   int i = ioctl(fd, TIOCGWINSZ, ws);
   if(i < 0){
-    logerror("TIOCGWINSZ failed on %d (%s)\n", fd, strerror(errno));
+    logerror("TIOCGWINSZ failed on %d (%s)", fd, strerror(errno));
     return -1;
   }
   if(ws->ws_row <= 0 || ws->ws_col <= 0){
-    logerror("Bogus return from TIOCGWINSZ on %d (%d/%d)\n",
+    logerror("bogon from TIOCGWINSZ on %d (%d/%d)",
              fd, ws->ws_row, ws->ws_col);
     return -1;
   }
@@ -1462,19 +1462,19 @@ int cbreak_mode(tinfo* ti){
   modtermios.c_lflag &= (~ECHO & ~ICANON);
   modtermios.c_iflag &= ~ICRNL;
   if(tcsetattr(ttyfd, TCSANOW, &modtermios)){
-    logerror("Error disabling echo / canonical on %d (%s)\n", ttyfd, strerror(errno));
+    logerror("error disabling echo / canonical on %d (%s)", ttyfd, strerror(errno));
     return -1;
   }
 #else
   // we don't yet have a way to take Cygwin/MSYS2 out of canonical mode FIXME.
   DWORD mode;
   if(!GetConsoleMode(ti->inhandle, &mode)){
-    logerror("error acquiring input mode\n");
+    logerror("error acquiring input mode");
     return -1;
   }
   mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
   if(!SetConsoleMode(ti->inhandle, mode)){
-    logerror("error setting input mode\n");
+    logerror("error setting input mode");
     return -1;
   }
 #endif
@@ -1486,9 +1486,9 @@ int putenv_term(const char* termname){
   #define ENVVAR "TERM"
   const char* oldterm = getenv(ENVVAR);
   if(oldterm){
-    logdebug("replacing %s value %s with %s\n", ENVVAR, oldterm, termname);
+    logdebug("replacing %s value %s with %s", ENVVAR, oldterm, termname);
   }else{
-    loginfo("provided %s value %s\n", ENVVAR, termname);
+    loginfo("provided %s value %s", ENVVAR, termname);
   }
   if(oldterm && strcmp(oldterm, termname) == 0){
     return 0;
@@ -1499,7 +1499,7 @@ int putenv_term(const char* termname){
   }
   int c = putenv(buf);
   if(c){
-    logerror("couldn't export %s\n", buf);
+    logerror("couldn't export %s", buf);
   }
   free(buf);
   return c;
diff --git a/src/lib/tree.c b/src/lib/tree.c
index e86ae484b..b66b245a4 100644
--- a/src/lib/tree.c
+++ b/src/lib/tree.c
@@ -168,7 +168,7 @@ nctree_add_internal(nctree* n, nctree_int_item* nii, const unsigned* spec,
   unsigned depth = 0;
   while(p[1] != UINT_MAX){ // we know p[0] isn't UINT_MAX
     if(*p >= nii->subcount){
-      logerror("invalid path element (%u >= %u)\n", *p, nii->subcount);
+      logerror("invalid path element (%u >= %u)", *p, nii->subcount);
       return -1;
     }
     nii = &nii->subs[*p];
@@ -178,7 +178,7 @@ nctree_add_internal(nctree* n, nctree_int_item* nii, const unsigned* spec,
   // we're at the node into which |add| ought be inserted
   // this last one can be equal to subcount; we're placing it at the end
   if(*p > nii->subcount){
-    logerror("invalid path element (%u >= %u)\n", *p, nii->subcount);
+    logerror("invalid path element (%u >= %u)", *p, nii->subcount);
     return -1;
   }
   struct nctree_int_item* tmparr = realloc(nii->subs, sizeof(*nii->subs) * (nii->subcount + 1));
@@ -211,15 +211,15 @@ nctree_add_internal(nctree* n, nctree_int_item* nii, const unsigned* spec,
 int nctree_add(nctree* n, const unsigned* spec, const struct nctree_item* add){
   // it's illegal to pass an empty path for addition; one must pass { 0, UINT_MAX }
   if(spec[0] == UINT_MAX){
-    logerror("invalid empty path\n");
+    logerror("invalid empty path");
     return -1;
   }
   if(add->subs){
-    logerror("invalid subs %p\n", add->subs);
+    logerror("invalid subs %p", add->subs);
     return -1;
   }
   if(add->subcount){
-    logerror("invalid subcount %u\n", add->subcount);
+    logerror("invalid subcount %u", add->subcount);
     return -1;
   }
   if(nctree_add_internal(n, &n->items, spec, add)){
@@ -242,7 +242,7 @@ int nctree_del(nctree* n, const unsigned* spec){
   const unsigned* p = spec;
   while(*p != UINT_MAX){
     if(*p >= nii->subcount){
-      logerror("invalid path element (%u >= %u)\n", *p, nii->subcount);
+      logerror("invalid path element (%u >= %u)", *p, nii->subcount);
       return -1;
     }
     parent = nii;
@@ -267,23 +267,23 @@ int nctree_del(nctree* n, const unsigned* spec){
 
 nctree* nctree_create(ncplane* n, const nctree_options* opts){
   if(opts->flags){
-    logwarn("Passed invalid flags 0x%016" PRIx64 "\n", opts->flags);
+    logwarn("passed invalid flags 0x%016" PRIx64, opts->flags);
   }
   if(n == notcurses_stdplane(ncplane_notcurses(n))){
-    logerror("can't use the standard plane\n");
+    logerror("can't use the standard plane");
     goto error;
   }
   if(opts->nctreecb == NULL){
-    logerror("Can't use NULL callback\n");
+    logerror("can't use NULL callback");
     goto error;
   }
   if(opts->indentcols < 0){
-    logerror("Can't indent negative columns\n");
+    logerror("can't indent negative columns");
     goto error;
   }
   nctree* ret = nctree_inner_create(n, opts);
   if(ret == NULL){
-    logerror("Couldn't prepare nctree\n");
+    logerror("couldn't prepare nctree");
     goto error;
   }
   return ret;
diff --git a/src/lib/unixsig.c b/src/lib/unixsig.c
index b89dcdc9e..068ca1c34 100644
--- a/src/lib/unixsig.c
+++ b/src/lib/unixsig.c
@@ -37,7 +37,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
   // don't register ourselves if we don't intend to set up signal handlers
   // we expect NULL (nothing registered), and want to register nc
   if(!atomic_compare_exchange_strong(&signal_nc, &expected, vnc)){
-    logpanic("%p is already registered for signals (provided %p)\n", expected, vnc);
+    logpanic("%p is already registered for signals (provided %p)", expected, vnc);
     return -1;
   }
   return 0;
@@ -113,7 +113,7 @@ int drop_signals(void* nc){
       alt_signal_stack.ss_flags = SS_DISABLE;
       if(sigaltstack(&alt_signal_stack, NULL)){
         if(errno != EPERM){
-          fprintf(stderr, "couldn't remove alternate signal stack (%s)\n", strerror(errno));
+          fprintf(stderr, "couldn't remove alternate signal stack (%s)", strerror(errno));
         }
       }
       free(alt_signal_stack.ss_sp);
@@ -123,7 +123,7 @@ int drop_signals(void* nc){
   }
   pthread_mutex_unlock(&lock);
   if(ret){
-    fprintf(stderr, "Signals weren't registered for %p (had %p)\n", nc, expected);
+    fprintf(stderr, "signals weren't registered for %p (had %p)", nc, expected);
   }
   // we might not have established any handlers in setup_signals(); always
   // return 0 here, for now...
@@ -181,7 +181,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
   // don't register ourselves if we don't intend to set up signal handlers
   // we expect NULL (nothing registered), and want to register nc
   if(!atomic_compare_exchange_strong(&signal_nc, &expected, nc)){
-    loginfo("%p is already registered for signals (provided %p)\n", expected, nc);
+    fprintf(stderr, "%p is already registered for signals (provided %p)" NL, expected, nc);
     return -1;
   }
   pthread_mutex_lock(&lock);
@@ -196,7 +196,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
     if(ret){
       atomic_store(&signal_nc, NULL);
       pthread_mutex_unlock(&lock);
-      fprintf(stderr, "error installing term signal handler (%s)\n", strerror(errno));
+      fprintf(stderr, "error installing term signal handler (%s)" NL, strerror(errno));
       return -1;
     }
     // we're not going to be restoring the old mask at exit, as who knows,
@@ -207,12 +207,12 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
   if(!no_quit_sigs){
     alt_signal_stack.ss_sp = malloc(alt_signal_stack.ss_size);
     if(alt_signal_stack.ss_sp == NULL){
-      fprintf(stderr, "warning: couldn't create alternate signal stack (%s)\n", strerror(errno));
+      fprintf(stderr, "warning: couldn't create alternate signal stack (%s)" NL, strerror(errno));
     }else{
       alt_signal_stack.ss_size = SIGSTKSZ * 4;
       alt_signal_stack.ss_flags = 0;
       if(sigaltstack(&alt_signal_stack, NULL)){
-        fprintf(stderr, "warning: couldn't set up alternate signal stack (%s)\n", strerror(errno));
+        fprintf(stderr, "warning: couldn't set up alternate signal stack (%s)" NL, strerror(errno));
         free(alt_signal_stack.ss_sp);
         alt_signal_stack.ss_sp = NULL;
       }
@@ -242,7 +242,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
     if(ret){
       atomic_store(&signal_nc, NULL);
       pthread_mutex_unlock(&lock);
-      fprintf(stderr, "Error installing fatal signal handlers (%s)\n", strerror(errno));
+      fprintf(stderr, "error installing fatal signal handlers (%s)" NL, strerror(errno));
       return -1;
     }
     handling_fatals = true;
diff --git a/src/lib/util.c b/src/lib/util.c
index eb17bb9e9..314427b46 100644
--- a/src/lib/util.c
+++ b/src/lib/util.c
@@ -24,11 +24,11 @@ int set_loglevel_from_env(ncloglevel_e* llptr){
   char* endl;
   long l = strtol(ll, &endl, 10);
   if(l < NCLOGLEVEL_PANIC || l > NCLOGLEVEL_TRACE){
-    logpanic("Illegal NOTCURSES_LOGLEVEL: %s\n", ll);
+    logpanic("illegal NOTCURSES_LOGLEVEL: %s", ll);
     return -1;
   }
   *llptr = l;
-  loginfo("Got loglevel from environment: %ld\n", l);
+  loginfo("got loglevel from environment: %ld", l);
   return 0;
 }
 
@@ -51,7 +51,7 @@ char* notcurses_accountname(void){
     return NULL;
   }
   if(!GetUserNameExA(NameSamCompatible, un, &unlen)){
-    logerror("couldn't get user name\n");
+    logerror("couldn't get user name");
     free(un);
     return NULL;
   }
@@ -96,7 +96,7 @@ char* notcurses_osversion(void){
 #else
   struct utsname uts;
   if(uname(&uts)){
-    logerror("failure invoking uname (%s)\n", strerror(errno));
+    logerror("failure invoking uname (%s)", strerror(errno));
     return NULL;
   }
   const size_t nlen = strlen(uts.sysname);
diff --git a/src/lib/visual.c b/src/lib/visual.c
index 0843ba62e..93e77ff93 100644
--- a/src/lib/visual.c
+++ b/src/lib/visual.c
@@ -55,7 +55,7 @@ ncvisual* ncvisual_from_file(const char* filename){
   }
   ncvisual* n = visual_implementation->visual_from_file(filename);
   if(n == NULL){
-    logerror("error loading %s\n", filename);
+    logerror("error loading %s", filename);
   }
   return n;
 }
@@ -68,7 +68,7 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale,
   }
   int ret = visual_implementation->visual_stream(nc, ncv, timescale, streamer, vopts, curry);
   if(ret < 0){
-    logerror("error streaming media\n");
+    logerror("error streaming media");
   }
   return ret;
 }
@@ -209,7 +209,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
                         unsigned* outy, unsigned* outx,
                         int* placey, int* placex){
   if(ti == NULL && n == NULL){
-    logerror("got NULL for both sources\n");
+    logerror("got NULL for both sources");
     return -1;
   }
   struct ncvisual_options fakevopts;
@@ -219,21 +219,21 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
   }
   // check basic vopts preconditions
   if(vopts->flags >= (NCVISUAL_OPTION_NOINTERPOLATE << 1u)){
-    logwarn("warning: unknown ncvisual options %016" PRIx64 "\n", vopts->flags);
+    logwarn("warning: unknown ncvisual options %016" PRIx64, vopts->flags);
   }
   if((vopts->flags & NCVISUAL_OPTION_CHILDPLANE) && !vopts->n){
-    logerror("requested child plane with NULL n\n");
+    logerror("requested child plane with NULL n");
     return -1;
   }
   if(vopts->flags & NCVISUAL_OPTION_HORALIGNED){
     if(vopts->x < NCALIGN_UNALIGNED || vopts->x > NCALIGN_RIGHT){
-      logerror("bad x %d for horizontal alignment\n", vopts->x);
+      logerror("bad x %d for horizontal alignment", vopts->x);
       return -1;
     }
   }
   if(vopts->flags & NCVISUAL_OPTION_VERALIGNED){
     if(vopts->y < NCALIGN_UNALIGNED || vopts->y > NCALIGN_RIGHT){
-      logerror("bad y %d for vertical alignment\n", vopts->y);
+      logerror("bad y %d for vertical alignment", vopts->y);
       return -1;
     }
   }
@@ -249,7 +249,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
   // determine our blitter
   *bset = rgba_blitter(ti, vopts);
   if(!*bset){
-    logerror("couldn't get a blitter for %d\n", vopts ? vopts->blitter : NCBLIT_DEFAULT);
+    logerror("couldn't get a blitter for %d", vopts ? vopts->blitter : NCBLIT_DEFAULT);
     return -1;
   }
   const ncpile* p = vopts->n ? ncplane_pile_const(vopts->n) : NULL;
@@ -273,13 +273,13 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
   geom->leny = vopts->leny;
   *placey = vopts->y;
   *placex = vopts->x;
-  logdebug("vis %ux%u+%ux%u %p\n", geom->begy, geom->begx, geom->leny, geom->lenx, n->data);
+  logdebug("vis %ux%u+%ux%u %p", geom->begy, geom->begx, geom->leny, geom->lenx, n->data);
   if(n->data == NULL){
-    logerror("no data in visual\n");
+    logerror("no data in visual");
     return -1;
   }
   if(geom->begx >= n->pixx || geom->begy >= n->pixy){
-    logerror("visual too large %u > %d or %u > %d\n", geom->begy, n->pixy, geom->begx, n->pixx);
+    logerror("visual too large %u > %d or %u > %d", geom->begy, n->pixy, geom->begx, n->pixx);
     return -1;
   }
   if(geom->lenx == 0){ // 0 means "to the end"; use all available source material
@@ -289,11 +289,11 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
     geom->leny = n->pixy - geom->begy;
   }
   if(geom->lenx <= 0 || geom->leny <= 0){ // no need to draw zero-size object, exit
-    logerror("zero-size object %d %d\n", geom->leny, geom->lenx);
+    logerror("zero-size object %d %d", geom->leny, geom->lenx);
     return -1;
   }
   if(geom->begx + geom->lenx > n->pixx || geom->begy + geom->leny > n->pixy){
-    logerror("geometry too large %d > %d or %d > %d\n", geom->begy + geom->leny, n->pixy, geom->begx + geom->lenx, n->pixx);
+    logerror("geometry too large %d > %d or %d > %d", geom->begy + geom->leny, n->pixy, geom->begx + geom->lenx, n->pixx);
     return -1;
   }
   if((*bset)->geom == NCBLIT_PIXEL){
@@ -301,37 +301,37 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
       // FIXME does this work from direct mode?
       if(vopts->n == notcurses_stdplane_const(ncplane_notcurses_const(vopts->n))){
         if(!(vopts->flags & NCVISUAL_OPTION_CHILDPLANE)){
-          logerror("won't blit bitmaps to the standard plane\n");
+          logerror("won't blit bitmaps to the standard plane");
           return -1;
         }
       }
       if(vopts->y && !(vopts->flags & (NCVISUAL_OPTION_VERALIGNED | NCVISUAL_OPTION_CHILDPLANE))){
-        logerror("non-origin y placement %d for sprixel\n", vopts->y);
+        logerror("non-origin y placement %d for sprixel", vopts->y);
         return -1;
       }
       if(vopts->x && !(vopts->flags & (NCVISUAL_OPTION_HORALIGNED | NCVISUAL_OPTION_CHILDPLANE))){
-        logerror("non-origin x placement %d for sprixel\n", vopts->x);
+        logerror("non-origin x placement %d for sprixel", vopts->x);
         return -1;
       }
       if(vopts->pxoffy >= geom->cdimy){
-        logerror("pixel y-offset %d too tall for cell %d\n", vopts->pxoffy, geom->cdimy);
+        logerror("pixel y-offset %d too tall for cell %d", vopts->pxoffy, geom->cdimy);
         return -1;
       }
       if(vopts->pxoffx >= geom->cdimx){
-        logerror("pixel x-offset %d too wide for cell %d\n", vopts->pxoffx, geom->cdimx);
+        logerror("pixel x-offset %d too wide for cell %d", vopts->pxoffx, geom->cdimx);
         return -1;
       }
       if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
         // FIXME clamp to sprixel limits
         unsigned rows = ((geom->leny + geom->cdimy - 1) / geom->cdimy) + !!vopts->pxoffy;
         if(rows > ncplane_dim_y(vopts->n)){
-          logerror("sprixel too tall %d for plane %d\n", geom->leny + vopts->pxoffy,
+          logerror("sprixel too tall %d for plane %d", geom->leny + vopts->pxoffy,
                    ncplane_dim_y(vopts->n) * geom->cdimy);
           return -1;
         }
         unsigned cols = ((geom->lenx + geom->cdimx - 1) / geom->cdimx) + !!vopts->pxoffx;
         if(cols > ncplane_dim_x(vopts->n)){
-          logerror("sprixel too wide %d for plane %d\n", geom->lenx + vopts->pxoffx,
+          logerror("sprixel too wide %d for plane %d", geom->lenx + vopts->pxoffx,
                    ncplane_dim_x(vopts->n) * geom->cdimx);
           return -1;
         }
@@ -366,7 +366,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
         *disppixx = geom->lenx + vopts->pxoffx;
         *disppixy = geom->leny + vopts->pxoffy;
       }
-      logdebug("pixel prescale: %d %d %d %d\n", n->pixy, n->pixx, *disppixy, *disppixx);
+      logdebug("pixel prescale: %d %d %d %d", n->pixy, n->pixx, *disppixy, *disppixx);
       if(scaling == NCSCALE_SCALE || scaling == NCSCALE_SCALE_HIRES){
         clamp_to_sixelmax(ti, disppixy, disppixx, outy, scaling);
         scale_visual(n, disppixy, disppixx);
@@ -381,14 +381,14 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
       *disppixx -= vopts->pxoffx;
       *disppixy -= vopts->pxoffy;
     }
-    logdebug("pblit: %dx%d ← %dx%d of %d/%d stride %u @%dx%d %p %u\n", *disppixy, *disppixx, geom->begy, geom->begx, n->pixy, n->pixx, n->rowstride, *placey, *placex, n->data, geom->cdimx);
+    logdebug("pblit: %dx%d ← %dx%d of %d/%d stride %u @%dx%d %p %u", *disppixy, *disppixx, geom->begy, geom->begx, n->pixy, n->pixx, n->rowstride, *placey, *placex, n->data, geom->cdimx);
     geom->rpixy = *disppixy;
     geom->rpixx = *disppixx;
     geom->rcellx = *outx / geom->cdimx + !!(*outx % geom->cdimx);
     geom->rcelly = *outy / geom->cdimy + !!(*outy % geom->cdimy);
   }else{ // cellblit
     if(vopts->pxoffx || vopts->pxoffy){
-      logerror("pixel offsets cannot be used with cell blitting\n");
+      logerror("pixel offsets cannot be used with cell blitting");
       return -1;
     }
     unsigned dispcols, disprows;
@@ -441,7 +441,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
     geom->rcellx = dispcols / geom->scalex + !!(dispcols % geom->scalex);
     geom->rcelly = disprows / geom->scaley + !!(disprows % geom->scaley);
   }
-  logdebug("rgeom: %d %d %d %d @ %d/%d (%d on %p)\n", geom->rcelly, geom->rcellx,
+  logdebug("rgeom: %d %d %d %d @ %d/%d (%d on %p)", geom->rcelly, geom->rcellx,
            geom->rpixy, geom->rpixx, *placey, *placex, (*bset)->geom, vopts->n);
   return 0;
 }
@@ -714,13 +714,13 @@ int ncvisual_rotate(ncvisual* ncv, double rads){
   int bboffy = 0;
   int bboffx = 0;
   if(ncvisual_bounding_box(ncv, &bby, &bbx, &bboffy, &bboffx) <= 0){
-    logerror("Couldn't find a bounding box\n");
+    logerror("couldn't find a bounding box");
     return -1;
   }
   int bbarea;
   bbarea = rotate_bounding_box(stheta, ctheta, &bby, &bbx, &bboffy, &bboffx);
   if(bbarea <= 0){
-    logerror("Couldn't rotate the visual (%d, %d, %d, %d)\n", bby, bbx, bboffy, bboffx);
+    logerror("couldn't rotate the visual (%d, %d, %d, %d)", bby, bbx, bboffy, bboffx);
     return -1;
   }
   int bbcentx = bbx, bbcenty = bby;
@@ -772,7 +772,7 @@ pad_for_image(size_t stride, int cols){
 
 ncvisual* ncvisual_from_rgba(const void* rgba, int rows, int rowstride, int cols){
   if(rowstride % 4){
-    logerror("Rowstride %d not a multiple of 4\n", rowstride);
+    logerror("rowstride %d not a multiple of 4", rowstride);
     return NULL;
   }
   ncvisual* ncv = ncvisual_create();
@@ -832,7 +832,7 @@ ncvisual* ncvisual_from_rgb_packed(const void* rgba, int rows, int rowstride,
 ncvisual* ncvisual_from_rgb_loose(const void* rgba, int rows, int rowstride,
                                   int cols, int alpha){
   if(rowstride % 4){
-    logerror("Rowstride %d not a multiple of 4\n", rowstride);
+    logerror("rowstride %d not a multiple of 4", rowstride);
     return NULL;
   }
   ncvisual* ncv = ncvisual_create();
@@ -894,11 +894,11 @@ ncvisual* ncvisual_from_palidx(const void* pdata, int rows, int rowstride,
                                int cols, int palsize, int pstride,
                                const uint32_t* palette){
   if(rowstride % pstride){
-    logerror("bad pstride (%d) for rowstride (%d)\n", pstride, rowstride);
+    logerror("bad pstride (%d) for rowstride (%d)", pstride, rowstride);
     return NULL;
   }
   if(palsize > 256 || palsize <= 0){
-    logerror("palettes size (%d) is unsupported\n", palsize);
+    logerror("palettes size (%d) is unsupported", palsize);
     return NULL;
   }
   ncvisual* ncv = ncvisual_create();
@@ -917,7 +917,7 @@ ncvisual* ncvisual_from_palidx(const void* pdata, int rows, int rowstride,
         if(palidx >= palsize){
           free(data);
           ncvisual_destroy(ncv);
-          logerror("invalid palette idx %d >= %d\n", palidx, palsize);
+          logerror("invalid palette idx %d >= %d", palidx, palsize);
           return NULL;
         }
         uint32_t src = palette[palidx];
@@ -975,7 +975,7 @@ ncplane* ncvisual_render_cells(ncvisual* ncv, const struct blitset* bset,
                                int placey, int placex,
                                ncvgeom* geom, ncplane* n,
                                uint64_t flags, uint32_t transcolor){
-  logdebug("cblit: rows/cols: %dx%d plane: %d/%d pix: %d/%d\n", geom->rcelly, geom->rcellx, ncplane_dim_y(n), ncplane_dim_x(n), geom->rpixy, geom->rpixx);
+  logdebug("cblit: rows/cols: %dx%d plane: %d/%d pix: %d/%d", geom->rcelly, geom->rcellx, ncplane_dim_y(n), ncplane_dim_x(n), geom->rpixy, geom->rpixx);
   blitterargs bargs;
   bargs.transcolor = transcolor;
   bargs.begy = geom->begy;
@@ -1012,7 +1012,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
                                 int placey, int placex, const ncvgeom* geom,
                                 ncplane* n, uint64_t flags, uint32_t transcolor,
                                 int pxoffy, int pxoffx){
-  logdebug("pblit: rows/cols: %dx%d plane: %d/%d\n", geom->rcelly, geom->rcellx, ncplane_dim_y(n), ncplane_dim_x(n));
+  logdebug("pblit: rows/cols: %dx%d plane: %d/%d", geom->rcelly, geom->rcellx, ncplane_dim_y(n), ncplane_dim_x(n));
   const tinfo* ti = &nc->tcache;
   blitterargs bargs;
   bargs.transcolor = transcolor;
@@ -1101,7 +1101,7 @@ ncplane* ncvisual_blit(notcurses* nc, ncvisual* ncv, const struct ncvisual_optio
     memset(&fakevopts, 0, sizeof(fakevopts));
     vopts = &fakevopts;
   }
-  loginfo("inblit %dx%d %d@%d %dx%d @ %dx%d %p\n", ncv->pixy, ncv->pixx, vopts->y, vopts->x,
+  loginfo("inblit %dx%d %d@%d %dx%d @ %dx%d %p", ncv->pixy, ncv->pixx, vopts->y, vopts->x,
           vopts->leny, vopts->lenx, vopts->begy, vopts->begx, vopts->n);
   ncvgeom geom;
   const struct blitset* bset;
@@ -1138,7 +1138,7 @@ ncplane* ncvisual_blit(notcurses* nc, ncvisual* ncv, const struct ncvisual_optio
       nopts.flags |= NCPLANE_OPTION_VERALIGNED;
       nopts.y = vopts->y;
     }
-    loginfo("placing new plane: %d/%d @ %d/%d 0x%016" PRIx64 "\n", nopts.rows, nopts.cols, nopts.y, nopts.x, nopts.flags);
+    loginfo("placing new plane: %d/%d @ %d/%d 0x%016" PRIx64, nopts.rows, nopts.cols, nopts.y, nopts.x, nopts.flags);
     if(n == NULL){
       n = ncpile_create(nc, &nopts);
     }else{
@@ -1150,7 +1150,7 @@ ncplane* ncvisual_blit(notcurses* nc, ncvisual* ncv, const struct ncvisual_optio
     placey = 0;
     placex = 0;
   }
-  logdebug("blit to plane %p at %d/%d geom %dx%d\n", n, ncplane_abs_y(n), ncplane_abs_x(n), ncplane_dim_y(n), ncplane_dim_x(n));
+  logdebug("blit to plane %p at %d/%d geom %dx%d", n, ncplane_abs_y(n), ncplane_abs_x(n), ncplane_dim_y(n), ncplane_dim_x(n));
   if(geom.blitter != NCBLIT_PIXEL){
     n = ncvisual_render_cells(ncv, bset, placey, placex,
                               &geom, n, vopts->flags, transcolor);
@@ -1219,11 +1219,11 @@ int ncvisual_simple_streamer(ncvisual* ncv, struct ncvisual_options* vopts,
 
 int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x, uint32_t pixel){
   if(y >= n->pixy){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   if(x >= n->pixx){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   n->data[y * (n->rowstride / 4) + x] = pixel;
@@ -1232,11 +1232,11 @@ int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x, uint32_t p
 
 int ncvisual_at_yx(const ncvisual* n, unsigned y, unsigned x, uint32_t* pixel){
   if(y >= n->pixy){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   if(x >= n->pixx){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   *pixel = n->data[y * (n->rowstride / 4) + x];
@@ -1304,11 +1304,11 @@ ncvisual_polyfill_core(ncvisual* n, unsigned y, unsigned x, uint32_t rgba, uint3
 
 int ncvisual_polyfill_yx(ncvisual* n, unsigned y, unsigned x, uint32_t rgba){
   if(y >= n->pixy){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   if(x >= n->pixx){
-    logerror("invalid coordinates %u/%u\n", y, x);
+    logerror("invalid coordinates %u/%u", y, x);
     return -1;
   }
   uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
diff --git a/src/lib/windows.c b/src/lib/windows.c
index 08859f1fe..a066fe4c7 100644
--- a/src/lib/windows.c
+++ b/src/lib/windows.c
@@ -47,24 +47,24 @@ int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
   ti->inhandle = GetStdHandle(STD_INPUT_HANDLE);
   ti->outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
   if(ti->inhandle == INVALID_HANDLE_VALUE){
-    logerror("couldn't get input handle\n");
+    logerror("couldn't get input handle");
     return -1;
   }
   if(ti->outhandle == INVALID_HANDLE_VALUE){
-    logerror("couldn't get output handle\n");
+    logerror("couldn't get output handle");
     return -1;
   }
   if(!SetConsoleOutputCP(CP_UTF8)){
-    logerror("couldn't set output page to utf8\n");
+    logerror("couldn't set output page to utf8");
     return -1;
   }
   if(!SetConsoleCP(CP_UTF8)){
-    logerror("couldn't set input page to utf8\n");
+    logerror("couldn't set input page to utf8");
     return -1;
   }
   DWORD inmode;
   if(!GetConsoleMode(ti->inhandle, &inmode)){
-    logerror("couldn't get input console mode\n");
+    logerror("couldn't get input console mode");
     return -1;
   }
   // we don't explicitly disable ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT
@@ -74,7 +74,7 @@ int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
             | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS
             | ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT;
   if(!SetConsoleMode(ti->inhandle, inmode)){
-    logerror("couldn't set input console mode\n");
+    logerror("couldn't set input console mode");
     return -1;
   }
   // if we're a true Windows Terminal, SetConsoleMode() ought succeed.
@@ -85,10 +85,10 @@ int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
                      | ENABLE_VIRTUAL_TERMINAL_PROCESSING
                      | DISABLE_NEWLINE_AUTO_RETURN
                      | ENABLE_LVB_GRID_WORLDWIDE)){
-    logerror("couldn't set output console mode\n");
+    logerror("couldn't set output console mode");
     return -1;
   }
-  loginfo("verified Windows ConPTY\n");
+  loginfo("verified Windows ConPTY");
   // ConPTY intercepts most control sequences. It does pass through XTVERSION
   // (for now), but since it responds to the DA1 itself, we usually get that
   // prior to any XTVERSION response. We instead key off of mintty's pretty
@@ -100,7 +100,7 @@ int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
       if(ver){
         ti->termversion = strdup(ver);
       }
-      loginfo("detected mintty %s\n", ti->termversion ? ti->termversion : "");
+      loginfo("detected mintty %s", ti->termversion ? ti->termversion : "");
       ti->qterm = TERMINAL_MINTTY;
       return 0;
     }


Test patch:
diff --git a/src/tests/egcpool.cpp b/src/tests/egcpool.cpp
index b7889cb72..90346fe3d 100644
--- a/src/tests/egcpool.cpp
+++ b/src/tests/egcpool.cpp
@@ -230,7 +230,6 @@ TEST_CASE("EGCpoolLong" * doctest::skip(true)) {
       }
       REQUIRE(loc == total);
       total += r + 1;
-      CHECK(egcpool_check_validity(&pool_, loc));
       CHECK((1u << 25) > loc);
       if(++wcs == 0x9fa5){
         wcs = 0x4e00;