Sublime Forum

macOS | Java: console, terminal, Terminus issues

#1

All, trying to set up my environment to begin Java development. Here I have a very simple class:

public class MyClass {
        public static void main(String args[]) {
            String name = "MyClass";
            System.out.println(name.toUpperCase());
        }
    }

When I build using the default JavaC, I see the following:

        /Users/me/.bash_profile: line 9: syntax error near unexpected token `('
        /Users/me/.bash_profile: line 9: `-a | perl -nle'/(\d+\.\d+\.\d+\.\d+)/ && print $1'/''
        [Finished in 403ms]

The first thing I notice is it builds, but with two error. But the (maybe?) obvious thing to me is bash is throwing an error, but I’m on a zsh Macbook Pro.

When I run with this build

{ 
    "shell_cmd":"javac $file_name && java $file_base_name"
 }

I see the same two bash errors as above, but I actually see output in the console (“MYCLASS”)

When I try to run a custom terminus build

{ 
    "target": "terminus_exec",
    "cancel": "terminus_cancel_build",
    "working_dir": "$folder",
    "shell_cmd":"javac $file_name && java $file_base_name"
 }

I see the bash errors again but see this:

/Users/me/.bash_profile: line 9: syntax error near unexpected token `('
/Users/me/.bash_profile: line 9: `-a | perl -nle'/(\d+\.\d+\.\d+\.\d+)/ && print $1'/''
error: file not found: MyClass.java
Usage: javac <options> <source files>
use --help for a list of possible options
[Finished in 0.21s with exit code 2]

And when I try this build to run it in the macOS terminal with runInTerminal.sh

{
	"shell_cmd": "runInTerminal.sh 'ls -l \"${packages}\"'",
    
	"env": {
		"PATH: "$PATH:/usr/local/bin"
	}	
}

(edit: removed ** in post markup where I tried to bold the PATH: line for clarity)

I simply see “No Build System” in the bottom status bar.

One thing to note in the final macOS terminal build running runInTerminal.sh, the entire PATH: line is highlighted red in Sublime (I chmod u+x runInTerminal.sh so it’s not permissions).

I think a lot of the wonkery is Sublime is expecting bash, when I’m running zsh.

I’ve been banging my head on this for a few hours and I’m at a loss. Any help is appreciated because I don’t want to run xcode or vs. THANKS!!! :grinning:

0 Likes

#2

I should add: build 4126, macOS Ventura 13.0

0 Likes

#3

All build systems (Terminus or default) use process.Popen() from the standard Python library to execute programs, and they both execute using bash as the execution environment, regardless of what your current shell is.

So, you see the bash errors because your .bash_profile file has an issue in it. As long as the program you’re executing doesn’t depend on anything set up in the shell it would still execute the program just fine. Note that on MacOS, the system shell is used at
startup to capture things like the PATH.

This is because the Java.sublime-build file that ships with Sublime only invokes javac and doesn’t try to execute the result; so if you use the default build you should see the bash errors but the only other output you would see is if your program doesn’t compile; otherwise a .class file is created but not executed.

It’s unclear what the name and location of your Java file is, but the default build has no working_dir field in it, which causes the build to default the working directory to the folder that the file being built is stored in.

So, this could happen if $folder is not the actual physical location of the file, since Java is very sensitive to file locations.

This error indicates that the sublime-build file is not valid JSON; thus Sublime can’t parse the file and doesn’t know how to execute the build. Your file is broken because there is a missing " in the PATH line. A fixed version is:

"PATH": "$PATH:/usr/local/bin",

A build that should compile and execute a single Java file would be something like (untested):

{
    "shell_cmd": "javac \"$file\" && java \"$file_base_name\"",
    "file_regex": "^(...*?):([0-9]*):?([0-9]*)",
    "selector": "source.java",
    "working_dir": "$file_path"
}

This is the base build but with the shell_cmd modified to also execute the file, and with a working_dir that specifies an explicit working dir. That last part isn’t needed unless you want to include the target line that runs this in Terminus, since Terminus defaults the working directory to a different place than Sublime’s internal exec command does.

Either way you will still see the bash errors unless you fix the bash profile issue that is making Bash unhappy.

1 Like

#4

Odat, thanks MUCH for the detailed reply, it’s appreciated!

[quote=“OdatNurd, post:3, topic:65751”]you see the bash errors because your .bash_profile file has an issue in it. As long as the program you’re executing doesn’t depend on anything set up in the shell it would still execute the program just fine. Note that on MacOS, the system shell is used at
startup to capture things like the PATH .[/quote]

Yep, stupid unix inexperience on my part. I had some old garbage in there and cleaned it out.

It works now, but only in Sublime’s terminal, which is weird – I thought shell_cmd invoked the local terminal?

The following DOES open the terminall:

{
	"shell_cmd": "runInTerminal.sh javac $file && java $file_base_name",
    
	"env": {
		"PATH": "$PATH:/usr/local/bin"
	}	
}

This invokes the terminal but prints “javac /Users/me/dev/MyClass.java” vs printing the System.out.println("Hello World).

Sorry for the inane questions and thanks again for your help!

0 Likes

#5

All Sublime builds send output to the internal output panel, which is just a text based panel that has output written into it (hence it does not allow input, interpret color sequences or do other things a terminal would do).

You can augment that via Terminus with a simple extension to the build system, in which case the build still occurs inside of a panel (or a tab depending on how you set it up) ; doing so would allow for input and a terminal experience from within Sublime.

For what you’re doing here, the issue is that the argument you provide to runInTerminal.sh needs to be a single string that represents the entire command to execute. If you want to chain commands as you’re doing here, you want something like:

"shell_cmd": "runInTerminal.sh 'javac $file && java $file_base_name'",

This is untested (my MacBook died), but generally speaking the single quotes here cause the remainder of the command line to be passed as a single argument.

0 Likes

#6

Yeah I think I tried that first (which should’ve been my clue that I was on the right track) and this was printed to terminal:

Error: Could not find or load main class MyClass
Caused by: java.lang.ClassNotFoundException: MyClass

0 Likes

#7

What does the whole build look like? That looks suspiciously like the java is executing in a place different than where the class file ended up.

0 Likes

#8
public class MyClass {
    public static void main(String args[]) {
        String name = "wOoHoO";
        System.out.println(name.toUpperCase());
    }
}

The build:

{
	"shell_cmd": "runInTerminal.sh 'javac $file && java $file_base_name'",
    
	"env": {
		"PATH": "$PATH:/usr/local/bin"
	}	
}

And the terminal:

jay@Ambleside ~ % javac /Users/jay/dev/MyClass.java && java MyClass
Error: Could not find or load main class MyClass
Caused by: java.lang.ClassNotFoundException: MyClass
jay@Ambleside ~ % pwd
/Users/jay
jay@Ambleside ~ % cd dev
jay@Ambleside dev % ls -l
total 56
-rw-r--r--@ 1 jay  staff  479 Oct 29 15:37 Focus.class
-rw-r--r--@ 1 jay  staff  156 Oct 29 15:37 Focus.java
drwxr-xr-x@ 5 jay  staff  160 Oct 30 21:50 IdeaProjects
-rw-r--r--@ 1 jay  staff  492 Nov  3 17:14 MyClass.class
-rw-r--r--@ 1 jay  staff  156 Nov  3 17:11 MyClass.java
-rw-r--r--@ 1 jay  staff  487 Oct 30 07:38 Test.class
-rw-r--r--@ 1 jay  staff  135 Oct 30 07:40 Test.java
-rw-r--r--  1 jay  staff  139 Oct 30 08:55 Test3.java
0 Likes

#9

If the top part of the output is the result of the build running, the problem is that ~ represents your home directory, but in order for java MyClass to work, the current directory needs to be /Users/jay/dev.

I would imagine that the Mac terminal doesn’t bother to respect what the current directory is at the point where you spawn it (since it seems vaguely pathological about allowing you to tell it anything at all about what it should ultimately do when it starts).

I would insert cd $file_path && at the front of the javac call so that it first swaps to the correct directory before the rest of the command proceeds and see how that works.

0 Likes