IndentingPerl

Indenting Perl is hard. Let’s go shopping!EdwardOConnor

Using a “better” mode will make indentation easier – CPerlMode instead of plain PerlMode.

You can force all attempts to invoke perl-mode to invoke cperl-mode instead via the following:

   (fset 'perl-mode 'cperl-mode)

Using perltidy

Most Perl indenting solutions revolve around customizing the settings of a particular mode. However, in some cases you need to normalize indententation of code in a team of heterogenous editor users. In other words I use perltidy at my work to indent perl code, and here is the elisp code I wrote to do it: PerlTidyElisp. – wjt

Basic indentation

Basic indentation can be changed using the variable cperl-indent-level:

    (setq cperl-indent-level 4)

Note that the variable cperl-indent-alist has a doc string that says it is not being used.

Treating parentheses as blocks

Version 5.0 of CPerlMode offers many improvements over older versions. For one, parenthetical blocks such as

    (
        'one',
        'two',
        'three'
    )

can be configured to be indented correctly. Get it at:

Note: As of 2016-02-22, the previous link is broken

(Can we expand on how to do this? I’d also like to see how to prevent cperl-mode from indenting like this

   function_call(
                  $arg1,
                  $arg2,
                  another_function_call(
                                         $arg3

and instead indent like this

    function_call(
        $arg1,
        $arg2,
        another_function_call(
            $arg3

--MichaelSoulier

Michael, I believe that with a recent CPerl you just need to

    (custom-set-variables
     '(cperl-indent-parens-as-block t))

AaronHarsh

I tried Aaron’s solution under 5.0, and it does exactly what you want, Michael. However you might also want

    '(cperl-close-paren-offset -2)

(or whatever your indent level is) so that the close parens are unindented far enough.

JeremyMuhlich

I’m happy with the following:

    (setq cperl-indent-level 4
          cperl-close-paren-offset -4
          cperl-continued-statement-offset 4
          cperl-indent-parens-as-block t
          cperl-tab-always-indent t)

which give me:

    function_call(
        $arg1,
        $arg2,
        another_function_call(
            $arg3
        )
    );

RossLonstein

Continued indentation

How do you solve this indenting problem? Notice the staircasing inside the “if()” after the first “print” and how the join and being outside the curly bracket doesnt have this problem. This occurs with cperl-mode, not perl-mode on every system I have access to.

    if(one() &&                                                                                                                  
           two())                                                                                                                
    {                                                                                                                            
        print                                                                                                                    
            one(),                                                                                                               
                two();                                                                                                                                                                                                                                        
        print                                                                                                                    
            join("",                                                                                                             
                 one(),                                                                                                          
                 two());                                                                                                         
    }                                                                                                                                                                                                                                                         
    print                                                                                                                        
        one(),                                                                                                                   
        two();                                                                                                                   

Thanks

GabrielMillerd

I didn’t realize that it worked as long as you’re on the top-level! Until now my solution has been to enclose the buffer in parenthesis (like your join call). – Alex

I have a problem with continuated indentation, I have

    (setq
        cperl-close-paren-offset -4
        cperl-continued-statement-offset 4
        cperl-indent-level 4
        cperl-indent-parens-as-block t
        cperl-tabs-always-indent t)

At top level, all the continuations are identically indented

    my $test = "a string"
        . "just"
        . " for"
        . "test";

But under a {}

    {
        my $test = "a string"
            . "just"
                . " for"
                    . "test";
    }

Is this a bug ?

DanielDehennin

I found default string indentation for concatenated strings very irritating but solved it by setting cperl-continued-statement-offset to 0. I’m not sure this is the best solution but at least now the result is readable. – Peter

Rather than hacking into the source, I think it’s better to just redefine that small function that you commented out to do the right thing; i.e. in .emacs, add:

 ;;load cperl, then work around indent issue
 (load-library "cperl-mode")
 (defun cperl-backward-to-start-of-continued-exp (lim)
  (if (memq (preceding-char) (append ")]}\"'`" nil))
      (forward-sexp -1))
  (beginning-of-line)
  (if (or (<= (point) lim) (< 0 cperl-continued-statement-offset))
      (goto-char (1+ lim)))
  (skip-chars-forward " \t"))

SteveSanbeg

The above bit from SteveSanbeg works great except that it screws up indents on continuing – pushing them far over to the right. Does anybody have a fix?

--JohnAnderson

Does anybody have an idea about how to influence the indentation of subs as arguments? I often run into situations like this:

    $img_ebox->signal_connect ('button-press-event', sub {
                                   my $bt = $_[1]->button;
                                   $mnu->popup(undef,undef,undef,undef,$bt, 0) if $bt == 3;
                               });

where cperl-mode pushes the body of the sub so far to the right that it is almost impossible to limit the line length to 80 chars.

PeterD

John; yes, it looks like just commenting a few parts out doesn’t work. I’ve looked at it a bit more, and wrote a simple version of that function from scratch, which so far seems to work pretty well:

 ;;load cperl, then work around indent issue
 (load-library "cperl-mode")
 (defun cperl-backward-to-start-of-continued-exp (lim)
   (goto-char (1+ lim))
   (forward-sexp)
   (beginning-of-line)
   (skip-chars-forward " \t")
 )

Peter; it looks like the more args you put on a line, the farther it indents; i.e.

	$img_ebox->signal_connect (
		'button-press-event', 
		sub {
			my $bt = $_[1]->button;
			$mnu->popup(undef,undef,undef,undef,$bt, 0) if $bt == 3;
		});

--SteveSanbeg

Above one by SteveSanbeg works fine and portable except the continued statement inside parentheses goes left from the opening parenthesis, so I made my hack into a function and also added a part to prevent continuation inside parentheses from being indented. This indents much like CC Mode.

Edit: Updated to my latest settings.

 (setq
  after-load-alist
  (append
   after-load-alist
   '((cperl-mode
      (defun cperl-backward-to-start-of-continued-exp (lim)
        (goto-char containing-sexp)
        (let ((sexp-start (following-char)))
          (forward-char)
          (skip-chars-forward " \t\n")
          (if (and (> (current-column) cperl-continued-statement-offset)
                   (memq sexp-start (append "([" nil)))
              (backward-char cperl-continued-statement-offset)))))
     )))

--KukiYomanai

Is there customization to have auto-indent like this:

    $something->create('sphere', sub {
        my ($c, @args) = @_;
        ...
    });

?

Answering to myself (using up-to-date https://github.com/jrockway/cperl-mode)

    (set-q cperl-indent-subs-specially nil)

My fix to continued indentation when cperl-indent-parens-as-block is in effect (fixes staircase and I hope introduces less side effects than other snippets listed here).

  (defadvice cperl-backward-to-start-of-continued-exp (after indentation-fix)
    (and (not (memq char-after '(?\) ?\})))
         (or (not is-block) (looking-back "^[ \t]+"))
         (> (current-column) cperl-continued-statement-offset)
         (backward-char cperl-continued-statement-offset)))

CategoryIndentation